<:I0,414,0,0><:S+273><:R1,15,1,0,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>Welcome to TADS 2.2!
<:I0,414,0,0><:S+273><:R1,15,1,0,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>This booklet is a supplement to the <+">TADS Author's Manual<-">, version 2.0, that describes all of the new features that have been added since version 2.0.
<:I0,414,0,0><:S+273><:R1,15,1,0,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>This booklet has two parts. Part I describes the additions and changes to TADS since version 2.0. If you're already familiar with version 2.1, you've already seen some of this material before; we've marked the sections that were also described in the vers
ion 2.1 release notes to make it easy to see at a glance what's new.
<:I0,414,0,0><:S+273><:R1,15,1,0,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Part II of this booklet is a full new chapter describing the TADS player command parser. Because so many of the new features since version 2.0 affect the parser, it would have been difficult to assemble a clear picture of how the parser works by reading un
connected descriptions of the numerous new features. Part II therefore is a complete description of the entire TADS parser, including all of the modern features, along with everything that was present in version 2.0.
@Header@<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#283,6624>"Replace" and "Modify" (2.1)
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Most game authors find that, when writing a substantial game, they can't avoid modifying objects in adv.t. While there's nothing intrinsically wrong with this, it creates a problem when a new version of TADS is released: you must either continue to use yo
ur old version of adv.t, or take the time to reconcile your changes with any changes we made in the new version. If you continue to use the old version, you won't be able to take advantage of any improvements or corrections we've made to adv.t.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>In version 2.1, we added a mechanism that lets you avoid this problem: the
<:f200,QCourier New,>replace<:f> and <:f200,QCourier New,>modify<:f> keywords. These new keywords let you make changes to objects that have been previously defined in the game program. In other words, you can
<:f200,QCourier New,>#include<:f> the standard definitions in adv.t, and then make changes to objects that the compiler has already finished compiling. Using these new keywords, you can make three types of changes to previously-defined objects: you can re
place a function entirely, you can replace an object entirely, or you can add to or change methods already defined in an object.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>To replace a function that's already been defined, you simply use the keyword
<:f200,QCourier New,>replace<:f> before the new function definition. Following the keyword
<:f200,QCourier New,>replace<:f> is an otherwise normal function definition.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>You can do exactly the same thing with objects. For example, you can entirely replace the
<:f200,QCourier New,>fastenVerb<:f> defined in adv.t:
<:s><:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Replacing an object entirely deletes the previous definition, including all inheritance information and vocabulary. The only properties of a replaced object are those defined in the replacement; the original definition is entirely discarded.
<:s><:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>You can also <+">modify<-"> an object, retaining its original definition, including inheritance information, vocabulary, and properties. This allows you to add new properties and vocabulary. You can also override properties, simply by redefining them in t
he new definition.
<:s><:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The most common addition to an object from adv.t will probably be new verb associations and added vocabulary:
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Note several things about this example. First, no superclass information can be specified in a
<:f200,QCourier New,>modify<:f> statement; this is because the superclass list for the modified object is the same as for the original object. Second, note that vocabulary has been added. The new vocabulary doesn't replace the original vocabulary, but sim
ply adds to the original vocabulary. Further note that the verb association pseudo-properties,
<:f200,QCourier New,>doAction<:f> and <:f200,QCourier New,>ioAction<:f>, are legal in a
<:f200,QCourier New,>modify<:f> statement. Any new <:f200,QCourier New,>doAction<:f> or
<:f200,QCourier New,>ioAction<:f> definitions are added to the original set of definitions.
<:s><:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>In a method that you redefine with <:f200,QCourier New,>modify<:f>, you can use
<:f200,QCourier New,>pass<:f> and <:f200,QCourier New,>inherited<:f> to refer to the
<+">replaced<-"> method in the original definition of the object. In essence, using
<:f200,QCourier New,>modify<:f> renames the original object, and then creates a new object under the original name; the new object is created as a subclass of the original (now unnamed) object. (There is no way to refer to the original, unmodified object d
irectly; you can only refer to it indirectly through the modified object.) Here's an example of using
<:f200,QCourier New,>pass<:f> with <:f200,QCourier New,>modify<:f>:
<:s><:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>You can also replace a property entirely, erasing all traces of the original definition of the property. The original definition is entirely forgotten--using
<:f200,QCourier New,>pass<:f> or <:f200,QCourier New,>inherited<:f> will refer to the method inherited by the original object. To do this, use the
<:f200,QCourier New,>replace<:f> keyword with the property itself:
<:I0,0,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>This would result in a different display for <:f200,QCourier New,>testObj.sdesc<:f>:
<:s><:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The <:f200,QCourier New,>replace<:f> keyword before the property definition tells the compiler to completely delete the previous definitions of the property. This allows you to completely replace the property, and not merely override it, meaning that
<:f200,QCourier New,>pass<:f> and <:f200,QCourier New,>inherited<:f> will refer to the property actually inherited from the superclass, and not the original definition of the property.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>TADS now allows you to create and delete objects dynamically at run-time. This is done through two new operators:
<:f200,QCourier New,>new<:f> and <:f200,QCourier New,>delete<:f>. To create a new object, use this syntax:
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>x := new bookItem;<:f>
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>This dynamically creates a new object whose superclass is <:f200,QCourier New,>bookItem<:f>. When this statement is executed, the runtime creates a new object, assigns its superclass to be
<:f200,QCourier New,>bookItem<:f>, and executes the <:f200,QCourier New,>construct<:f> method in the new object; this method can perform any creation-time setup that you wish to do. The default
<:f200,QCourier New,>construct<:f> method in the class <:f200,QCourier New,>thing<:f> in adv.t simply moves the new object into its location--this is necessary so that the
<:f200,QCourier New,>contents<:f> list of the location is updated to include the new object.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>An expression involving the operator <:f200,QCourier New,>new<:f> applied to a class can be used wherever an object expression can be used. When the expression is evaluated, a new object of the given class is created.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Note that you can create a new object that has no superclass by using the keyword
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>x := new object;<:f>
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>If you're familiar with C++ constructors, you should note an important difference between the
<:f200,QCourier New,>construct<:f> method and C++ constructors. A C++ constructor in a derived class will automatically call the construct in the base class (except for a virtual base class). The TADS
<:f200,QCourier New,>construct<:f> method does <+">not<-"></`>automatically call superclass
<:f200,QCourier New,>construct<:f> methods; instead, <:f200,QCourier New,>construct<:f> works exactly the same as any other TADS method. You can, of course, call the superclass
<:f200,QCourier New,>construct<:f> method explicitly using the <:f200,QCourier New,>inherited<:f> mechanism, just as with any other method. The same is true of the
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>A new object inherits all of the vocabulary of its superclass.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>To destroy an object create with <:f200,QCourier New,>new<:f>, use this syntax:
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>This first calls the <:f200,QCourier New,>destruct<:f> method of the object to notify it that it is about to be deleted, then destroys the object. Further references to the object are illegal, since its memory has been released (and thus may be given to an
other object). The default <:f200,QCourier New,>destruct<:f> method in the class
<:f200,QCourier New,>thing<:f> in adv.t moves the object into <:f200,QCourier New,>nil<:f>, which removes it from its container's
<:f200,QCourier New,>contents<:f> list--this is necessary so that the reference to the object in that list is removed.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Only objects created with <:f200,QCourier New,>new<:f> can be destroyed with
<:f200,QCourier New,>delete<:f>. Objects that are defined statically in your game's source file cannot be deleted at run-time.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Object creation and deletion works correctly with the UNDO mechanism. If the player uses UNDO after a move that created an object, the object will be destroyed; likewise, if a player uses UNDO after a turn that deletes an object, the object will be re-crea
ted with the same property values it had prior to deletion.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Similarly, dynamically-created objects are preserved across SAVE and RESTORE operations.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>Note that TADS does not perform any garbage collection on dynamically-created objects. The system is not capable of determining whether an object is accessible or not. Hence, if you lose track of any objects you create with
<:f200,QCourier New,>new<:f>, they will remain part of the game forever--they will even be saved along with saved games and restored when the games are restored. You must be careful to keep track of all objects you create to avoid filling all available mem
ory (and the swap file) with unreachable objects. Even though TADS will eventually swap inaccessible objects out of memory, the objects will consume object identifiers, which are a limited resource: only 65535 objects can be created within a game, includi
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>New built-in functions let you dynamically add to and delete from the vocabulary words of an object. You can also get the vocabulary words of an object at run-time.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>To add to an object's vocabulary, use the new <:f200,QCourier New,>addword()<:f> built-in function. This function takes three arguments: an object, a vocabulary property pointer, and a word to add. For example, to add "red" as an adjective to the object
<:f200,QCourier New,>myBook<:f>, you would do this:
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>To delete the same word, you would write a similar call to the new built-in function
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>You can add to and delete from the words of any object, including both static objects (explicitly defined in your source code) and dynamically-created objects (created with the operator
<:f200,QCourier New,>new<:f>).
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Changes made by <:f200,QCourier New,>addword()<:f> and <:f200,QCourier New,>delword()<:f> are tracked correctly by the UNDO mechanism, and are saved and restored along with saved games.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>To get the words belonging to an object, use the new <:f200,QCourier New,>getwords()<:f> built-in function. This function takes two arguments: an object, and a property pointer; it returns a list of (single-quoted) strings, which are the vocabulary words
for the object. For example, assume we define <:f200,QCourier New,>myBook<:f> as follows:
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Also assume we haven't made any calls to <:f200,QCourier New,>addword()<:f> or
<:f200,QCourier New,>delword()<:f> for <:f200,QCourier New,>myBook<:f>. In this case,
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>would return this list:
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Note that the order of the words in the list is not predictable, so you shouldn't expect the words to be in the same order as they were when you defined them in the source file, or in the same order as they were added with
@Header@<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#283,6624><:ZGettingVerbInfo><:Z~GettingVerbInfo>Getting Verb Information
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Another new built-in function lets you retrieve information on a verb. This new function,
<:f200,QCourier New,>verbinfo()<:f>, takes as parameters a <:f200,QCourier New,>deepverb<:f> object and an optional preposition object, and returns a list that gives the parser information for this verb.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>When you call <:f200,QCourier New,>verbinfo()<:f> with a single argument (a
<:f200,QCourier New,>deepverb<:f> object), the return value is a list with two elements, giving information on the
<:f200,QCourier New,>doAction<:f> definition for the <:f200,QCourier New,>deepverb<:f> object:
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>When you call <:f200,QCourier New,>verbinfo()<:f> with two arguments (the first is a
<:f200,QCourier New,>deepverb<:f> object, and the second is a preposition object), the return value is a list with four elements, giving information on the
<:f200,QCourier New,>ioAction<:f> definition for the <:f200,QCourier New,>deepverb<:f> object that matches the given preposition object:
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>4] <:f200,QCourier New,>true<:f> if this <:f200,QCourier New,>ioAction<:f> has
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>In either case, if the <:f200,QCourier New,>deepverb<:f> doesn't have a corresponding
<:f200,QCourier New,>doAction<:f> or <:f200,QCourier New,>ioAction<:f> method, the function returns
<:f200,QCourier New,>nil<:f>.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>As an example, suppose we define a verb that looks like this:
<:I0,432,0,0><:S+273><:R1,15,1,796,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>With this definition, <:f200,QCourier New,>verbinfo(pryVerb)<:f> would return this list, which provides information on the
<:I0,0,0,0><:S+273><:R1,15,1,796,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>verbinfo(pryVerb, withPrep)<:f> would return this list:
<:I0,432,0,0><:S+273><:R1,15,1,796,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>If the <:f200,QCourier New,>ioAction<:f> definition had included the
<:f200,QCourier New,><[>disambigDobjFirst]<:f> flag, the fourth element of the list would have been
<:f200,QCourier New,>true<:f>.
<:I0,432,0,0><:S+273><:R1,15,1,796,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Calling <:f200,QCourier New,>verbinfo()<:f> for <:f200,QCourier New,>pryVerb<:f> and any preposition other than
<:f200,QCourier New,>withPrep<:f> will return <:f200,QCourier New,>nil<:f>, because the verb doesn't define an
<:f200,QCourier New,>ioAction<:f> for any other preposition. Similarly, if the verb didn't have a
<:f200,QCourier New,>doAction<:f> method, <:f200,QCourier New,>verbinfo(pryVerb)<:f> would have returned
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1152,1,1512,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The ability to create new objects at run-time leads to some interesting problems involving indistinguishable objects. Although you could use
<:f200,QCourier New,>addword()<:f> to make your newly-created objects distinguishable from one another, this will not always be desirable; for example, if you create new gold pieces that serve as currency, you will probably not want them to be uniquely name
<:s><:I0,432,0,0><:R1,15,1,792,1,1152,1,1512,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>To support indistinguishable objects, especially those created dynamically at run-time, the system now has a property that you can set to indicate to the parser that an object does not need to be distinguished from others of the same class. The new propert
y is <:f200,QCourier New,>isEquivalent<:f>. When <:f200,QCourier New,>isEquivalent<:f> returns
<:f200,QCourier New,>true<:f> for an object, all other objects with the same
<+">immediate<-"> superclass are considered interchangeable by the parser. When a player uses one of these objects in a command, the parser will simply pick one arbitrarily and use it, without asking the player which one.
<:s><:I0,432,0,0><:R1,15,1,792,1,1152,1,1512,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>If a player uses a noun that is ambiguous with multiple equivalent items and one or more other items, the parser will need to disambiguate the objects as usual. In such cases, the parser's question will list the distinguishable items only once. For exampl
e, assume we have five gold coins that are all equivalent (in other words, they all have
<:f200,QCourier New,>isEquivalent<:f> set to <:f200,QCourier New,>true<:f>, and they all are immediate subclasses of the same class). Assume further that a silver coin and a bronze coin are also present in the room.
<:s><:I0,432,0,0><:R1,15,1,792,1,1152,1,1512,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624> You see a bronze coin, five gold coins, and a silver coin here.
<:s><:I0,432,0,0><:R1,15,1,792,1,1152,1,1512,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>Which coin do you mean, the bronze coin, a gold coin, or the silver coin?
<:s><:I0,432,0,0><:S+273><:R1,15,1,792,1,1152,1,1512,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Note that the objects which appear only once are listed with "the" (using the property
<:f200,QCourier New,>thedesc<:f>), while the indistinguishable objects are listed only once, with "a" (using
<:f200,QCourier New,>adesc<:f>).
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1152,1,1512,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The functions <:f200,QCourier New,>listcont<:f> and <:f200,QCourier New,>itemcnt<:f> in adv.t have been modified so that they list equivalent objects intelligently; the functions
<:f200,QCourier New,>isIndistinguishable<:f> and <:f200,QCourier New,>sayPrefixCount<:f> have been added to adv.t to help with counting and listing indistinguishable objects correctly. The contents of the Treasure Room are listed in the example above in th
e new format. Refer to these functions in adv.t for examples of recognizing objects as equivalent, counting equivalent objects, and treating a set of equivalent objects together as a set.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1152,1,1512,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Note that <:f200,QCourier New,>listcont<:f> uses the new property
<:f200,QCourier New,>pluraldesc<:f> to display the name of an object when more than one equivalent object is present. In the example above,
<:f200,QCourier New,>pluraldesc<:f> was used to list the gold coins. This property has been added to the class
<:f200,QCourier New,>thing<:f> in adv.t, but you may need to override it for some objects--the default implementation simply displays the
<:f200,QCourier New,>sdesc<:f> plus the letter "s."
@Header@<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#283,6624>Capturing Displayed Text
<:I0,432,0,0><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>TADS now has a feature that lets you capture the text displays that are generated by double-quoted strings and by the
<:f200,QCourier New,>say()<:f> built-in function. This feature allows you to examine the values of methods such as
<:f200,QCourier New,>ldesc<:f> and <:f200,QCourier New,>sdesc<:f>; since these methods display text, there is no direct way of manipulating their text as strings. The new output capture feature makes it possible for you to examine and manipulate any text t
hat ordinarily would simply be displayed.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>To use this new feature, you first tell TADS that you wish to begin capturing output by calling a new built-in function:
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>This begins capturing output. The return value is a status code that you use in a subsequent call to turn off output capturing; this status code allows output capturing calls to be "nested," since the status code allows the capturing status that was in eff
ect on a call to begin capturing to be restored on the subsequent call to end capturing. This status code is for use by TADS only--the only thing you do with it is use it in the subsequent call to end capturing.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>While output is being captured, any text that would normally be displayed is instead saved by the system. The user does not see any text displayed while capturing is in effect. After you begin capturing, simply call any methods whose displays you want to
examine; for example, you could call <:f200,QCourier New,>redbook.sdesc<:f> if you want to examine the short description of the object
<:f200,QCourier New,>redbook<:f>.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>After you've finished calling the methods whose displays you want to examine, end capturing by calling
<:f200,QCourier New,>outcapture()<:f> again, passing as the argument the status code returned by the first call:
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>This second call tells TADS to stop capturing output. The return value of this function is a (single-quoted) string containing all of the text that was displayed since the corresponding call to
<:f200,QCourier New,>outcapture(true)<:f>.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>When text is being captured, TADS expands all format strings (strings such as "%you%"), and processes "\^" and "\v" sequences (which convert the next character to upper- and lower-case, respectively). However, all other escape sequences (such as "\n" and "
\t") are left in the string intact.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>You can display the string returned from the call to <:f200,QCourier New,>outcapture(stat)<:f> using the
<:f200,QCourier New,>say()<:f> built-in function. This should result in the same text display that would have occurred if you hadn't turned on capturing.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>You can nest calls to <:f200,QCourier New,>outcapture()<:f>; as explained above, the status code returned from the first call is used to restore the capturing status of the previous call. The string returned by a call to turn off capturing includes only te
xt that was generated after the corresponding call to turn on capturing. Because calls to
<:f200,QCourier New,>outcapture()<:f> can be nested, you don't have to worry when using text capturing about whether any methods you're calling also use the function.
<:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Note that the system automatically turns off output capturing whenever it prompts the user for a command, for a missing direct or indirect object, or for disambiguation information. When the system turns off capturing, it clears the captured text, so any s
ubsequent calls to turn off capturing return empty strings. You therefore can only capture text within a single command line.
<:s><:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Many of the changes since version 2.0 have been made to the TADS player command parser. Since Part II of these release notes provides full documentation of the modern features of the parser, including new features as well as features that were present in v
ersion 2.0, we won't go into too much detail in this section. Instead, we'll summarize the changes that have been made, and refer you to the appropriate section in Part II.
<:s><:I0,432,0,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If you're not already familiar with the TADS parser, you shouldn't need to read this section at all, because everything described below is documented in Part II. This section is provided for users of past versions, so that you can see at a glance what's ne
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>validD<-!><+!>oList and validI<-!><+!>oList (2.1)<-!>
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>In version 2.1, we added a new mechanism for determining whether an object is accessible for a command. The new mechanism supplements the
<:f200,QCourier New,>validDo<:f> and <:f200,QCourier New,>validIo<:f> methods, which test a single object to determine if it's accessible for a verb. The added methods are
<:f200,QCourier New,>validDoList<:f> and <:f200,QCourier New,>validIoList<:f>; these methods return a list of valid direct objects and indirect objects (respectively) for a particular command. As with
<:f200,QCourier New,>validDo<:f> and <:f200,QCourier New,>validIo<:f>, these new methods are defined in the
<:f200,QCourier New,>deepverb<:f> object for a verb.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The new <:f200,QCourier New,>validDoList<:f> and <:f200,QCourier New,>validIoList<:f> methods are fully described the section on object resolution (page
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Note that this new mechanism, if you use it, requires that you use the new
<:f200,QCourier New,>floatingItem<:f> class for any object that uses a method for its
<:f200,QCourier New,>location<:f> property. The reason is that objects with non-object
<:f200,QCourier New,>location<:f> values are <+">not<-"> part of any
<:f200,QCourier New,>contents<:f> list, so they will not be included in any
<:f200,QCourier New,>validDoList<:f> or <:f200,QCourier New,>validIoList<:f> return value. You should make sure that any object in your game that has a method for its
<:f200,QCourier New,>location<:f> property includes <:f200,QCourier New,>floatingItem<:f> in its superclass list.
<+C><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The new class <:f200,QCourier New,>f<:f200,QCourier New,>loatingItem<:f> should be used for any object that uses a method for its
<:f200,QCourier New,>location<:f> property, because of the new <:f200,QCourier New,>validDoList<:f> and
<:f200,QCourier New,>validIoList<:f> validation mechanism, as described above. If you define an object with a method for its
<:f200,QCourier New,>location<:f> property, the object <+">must<-"></`>have
<:f200,QCourier New,>floatingItem<:f> among its superclasses in order for it to be accepted as a valid object for the verbs defined in adv.t.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>dobjGen and iobjGen (2.1)<-!>
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>In version 2.1, we enhanced the parsing process so that the TADS parser calls a general-purpose command handler in each object in a command prior to the normal verification and action method calls. These new general-purpose methods are intended to be "catc
h-all" handlers that let you treat all verbs, or any set of verbs, alike--since the same methods will be called in the objects regardless of the verb, you can give the same behavior to multiple verbs without having to explicitly code each verb handler indiv
idually. These new methods, <:f200,QCourier New,>dobjGen<:f> and
<:f200,QCourier New,>iobjGen<:f>, are described fully in part II in the section "General Verb Processing" (page
<:I0,432,0,0><:S+273><:R1,15,1,342,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Whenever the parser displays a command prompt, it now calls the <:f200,QCourier New,>commandPrompt<:f> function. This is a function that your game program can define. See the section on reading a command (page
<:X3,-16384;PageRef ReadingACommand>72<:X~3,-16384;PageRef ReadingACommand>) for details.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Several new functions have been added that let you customize messages that the parser generates. These functions are used to generate complex messages that are normally pieced together from multiple
<:f200,QCourier New,>parseError<:f> messages. Since the parser needs to build these messages from a series of pieces,
<:f200,QCourier New,>parseError<:f> lets you change the individual pieces, but not the overall method of construction--for example, it doesn't let you change the order of the phrases generated. These new functions address this problem.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>The new functions are <:f200,QCourier New,>parseError2<:f>, which lets you control the message displayed when an object doesn't understand a verb (because it doesn't define or inherit a verification method for the verb);
<:f200,QCourier New,>parseDefault<:f>, which lets you change the message generated when the parser is assuming a default object;
<:f200,QCourier New,>parseDisambig<:f>, which lets you control the message asking the player which of several possible objects should be used for a command; and
<:f200,QCourier New,>parseAskobj<:f>, which lets you change the message when the parser asks the player to supply a missing direct or indirect object. Note that
<:f200,QCourier New,>parseAskobj<:f> should no longer be used, because the more useful
<:f200,QCourier New,>parseAskobjActor<:f> function has been added; games written with
<:f200,QCourier New,>parseAskobj<:f> will still work correctly, but new games should use the modern function. These functions are all described in detail in Part II.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>parseAskobjActor Message Function
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>We added another new message customization function in version 2.2. This new function,
<:f200,QCourier New,>parseAskobjActor<:f>, is similar to <:f200,QCourier New,>parseAskobj<:f>, but receives the actor as a parameter. This allows you to generate a better message when the actor isn't
<:f200,QCourier New,>Me<:f>. See the section on verb templates (page
<:X3,-16384;PageRef VerbTemplates>85<:X~3,-16384;PageRef VerbTemplates>) for details.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>"Any" and "Either"<-!>
<:I0,432,0,0><:R><:#1638,6624>The parser now accepts noun phrases that begin with "any" or "either" (or different words that you define with an added slot in the
<:f200,QCourier New,>specialWords<:f> statement). The player can use "any" plus a singular noun phrase, or "any of" plus a plural noun phrase ("either" is equivalent); this instructs the parser to choose one object arbitrarily when the noun phrase refers t
o more than one object. See the section on noun phrases (page <:X3,-16384;PageRef NounPhrases>80<:X~3,-16384;PageRef NounPhrases>) for details.
<:s><:I0,432,0,0><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The compiler accepts new syntax that lets you redirect, with a single, concise declaration, the verification and action methods for a particular verb from one object to another object. For example, if you have a desk that contains a drawer, and you want th
e verbs "open" and "close" to be directed to the drawer when the player applies them to the desk, the new syntax lets you specify this indirection with these two lines in the definition of the desk object:
<:I0,432,0,0><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>This new syntax is described in Part II in the section on verb synonyms and redirection (page
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The parser calls a new property, <:f200,QCourier New,>multisdesc<:f>, when listing the current direct object while executing a command with multiple objects. For example:
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>put all in box
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>rubber raft: The raft is too large.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The object name listed before the response for each object is now displayed with
<:f200,QCourier New,>multisdesc<:f> (in previous versions, the parser used
<:f200,QCourier New,>sdesc<:f> for this purpose; for compatibility with existing games, the parser will still call
<:f200,QCourier New,>sdesc<:f> for any objects that don't define or inherit
<:f200,QCourier New,>multisdesc<:f>). This is the only place where
<:f200,QCourier New,>multisdesc<:f> is used, so if you want to customize this type of display, you can make changes to
<:f200,QCourier New,>multisdesc<:f> without any effect on the general
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The parser calls a new function, <:f200,QCourier New,>preparseCmd<:f>, before executing each individual command on a command line. This new command is similar to
<:f200,QCourier New,>preparse<:f>, but is more powerful for certain situations, because it is called with a list of words (the result of scanning the command line and breaking it into individual words), and is called with only the words making up a single c
ommand, rather than the entire command line. Of course, <:f200,QCourier New,>preparse<:f> still works as before.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Several new <:f200,QCourier New,>parseError<:f> codes have been added, and the default message generation process has been improved for certain cases. The main changes are to the messages that the parser generates when no
<:f200,QCourier New,>parseAskobjActor<:f> or <:f200,QCourier New,>parseAskobj<:f> functions are present. The full set of
<:f200,QCourier New,>parseError<:f> codes is listed on page <:X3,-16384;PageRef parseError>114<:X~3,-16384;PageRef parseError>, and the
<:f200,QCourier New,>parseAskobjActor<:f> function, and the new default messages generated when it's not present, are described in the section on verb templates in (page
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Multiple Actors are allowed on a Command Line<-!>
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The parser will now allow you to specify the actor to which a command is to be directed for each individual command on a command line. Previously, the parser only allowed the actor to be specified at the very beginning of the whole line, so any one command
line could include commands only to a single actor. This restriction has been removed; each individual command can specify its own actor. Any command that doesn't specify an actor is directed to the same actor as the previous command on the same line. T
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>go north. Joe, get the box. give it to Biff. Biff, open the box.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The command "go north" is directed to the player actor (<:f200,QCourier New,>Me<:f>). "Get the box" and "give it to Biff" are directed to Joe, and "open the box" is directed to Biff.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>Note that you can still direct each command to only a single actor.
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>More Notifiers, Daemons, and Fuses<-!>
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The number of notifiers (set with the <:f200,QCourier New,>notify()<:f> built-in function) that can be simultaneously active has been increased to 200 (the previous limit was 100). The limit on the number of simultaneously-active fuses has been lifted from
50 to 100, and the limit on the number of simultaneously-active daemons has likewise been lifted from 50 to 100.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The number of objects to which a single word can refer has been lifted from 100 to 200. If you've received an error message such as "The word 'door' refers to too many objects," you've encountered this limit. As the TADS parser scans a noun phrase, it mus
t build a list of the objects to which a particular object refers; these lists are limited in size. For this reason, you should avoid defining a word in your basic classes (such as
<:f200,QCourier New,>thing<:f>). Although this limit has not been removed entirely, we have raised it to make it less likely that you'll encounter it.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>You can now specify that the processing for an <:f200,QCourier New,>ioAction<:f> definition should resolve (disambiguate) the direct object first. Normally, TADS will disambiguate the indirect object first, and then resolve the direct objects with a known
indirect object. For some verbs, it's desirable to be able to resolve the direct object first, so that you can decide which indirect object to use based on the known direct object. The new
<:f200,QCourier New,>ioAction<:f> flag, <:f200,QCourier New,>disambigDobjFirst<:f>, allows you to tell TADS to reverse its normal object resolution order. The section on verb templates (page
<:X3,-16384;PageRef VerbTemplates>85<:X~3,-16384;PageRef VerbTemplates>) describes this new flag.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Two new methods have been added that give you more control over the process of disambiguating actors:
<:f200,QCourier New,>validActor<:f> and <:f200,QCourier New,>preferredActor<:f>. In previous versions of TADS, the parser disambiguated an actor as though the player were trying to "take" the actor--in other words, the parser used the
<:f200,QCourier New,>takeVerb<:f> disambiguation methods to determine if an object was valid as an actor. TADS now gives you more control over this process by calling these new methods, which are used only for actor disambiguation. The section on checking
for an actor (page <:X3,-16384;PageRef CheckActor>76<:X~3,-16384;PageRef CheckActor>) discusses these new methods.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>For compatibility with games written for versions prior to 2.2, if your objects don't define or inherit a
<:f200,QCourier New,>validActor<:f> method, the parser will continue to use the old mechanism.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The parser's handling of plurals has been improved. When you define a word as a plural, and the same word is used by another object as a noun, the parser failed to recognize the object with the noun in past versions. The parser will now try the plural fir
st; if no objects are found matching the plural usage, the parser will try the noun usage instead.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>"Of" can be used as a Preposition<-!>
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The word "of" can now be used as a preposition, even if it's defined as a special word in the "of" slot. The parser no longer considers "of" to be a reserved word; the parser only checks for the special meaning in noun phrases (such as "piece of paper") wh
en the context allows it. You can now create commands such as "accuse
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>When we introduced the new sentence format VERB PREP IOBJ DOBJ (introduced in version 2.1.1) created a problem when the same word was defined as both an adjective and a preposition. The problem was that the parser always attempted to interpret a phrase suc
h as "push off button," where "off" is defined as a preposition but also as an adjective for the button, with "off" as a preposition.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The parser has been changed so that the adjective affiliation is stronger. If an word that can be either a preposition or an adjective is used as part of a noun phrase that refers to at least one object, the parser will interpret the word as an adjective.
Only when the word doesn't form a noun phrase with subsequent words will it be interpreted as a preposition.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The parser now lets you prevent the player from using multiple words for a particular command; you can control whether multiple objects are acceptable separately for each verb. The parser calls the new method
<:f200,QCourier New,>rejectMultiDobj<:f> whenever the player uses a list of objects or "all" with a command; if this method returns
<:f200,QCourier New,>true<:f>, the parser ignores the command. The section on multiple objects (page
<:X3,-16384;PageRef MultipleObjects>99<:X~3,-16384;PageRef MultipleObjects>) discusses this new method.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The parser gives you greater control over the error message generated when a set of objects are visible but not accessible for a command. If you define a
<:f200,QCourier New,>cantReach<:f> method in a <:f200,QCourier New,>deepverb<:f> object, the parser will use that method rather than calling the
<:f200,QCourier New,>cantReach<:f> method for each inaccessible object. The section on object resolution (page
<:X3,-16384;PageRef ObjectResolution>94<:X~3,-16384;PageRef ObjectResolution>) describes this new method.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Using the Same Verb for Two Objects<-!>
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The parser now generates a warning if you use the same vocabulary word as a
<:f200,QCourier New,>verb<:f> property for multiple objects. The new message is TADS-452, "warning: same verb defined for two objects." If you define the same vocabulary word as a verb multiple times, the parser will arbitrarily use one of the
<:f200,QCourier New,>deepverb<:f> definitions, and ignore the others; if you weren't aware you were re-using a verb, it could be difficult to track down why your verb handlers were never being called. The new warning flags this situation for you.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Multiple Numbers and Strings<-!>
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The parser now properly sets the <:f200,QCourier New,>strObj<:f> or
<:f200,QCourier New,>numObj<:f> <:f200,QCourier New,>value<:f> property for each individual number of string in a command if more than one appears in a single command. For example:
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The <:f200,QCourier New,>value<:f> property of the <:f200,QCourier New,>numObj<:f> object will be set to 1 when processing the first number, 2 for the second, and 3 for the third, as you'd expect. In past versions of TADS, the
<:f200,QCourier New,>numObj<:f> and <:f200,QCourier New,>strObj<:f>
<:f200,QCourier New,>value<:f> properties were set only for the first number or string in a command.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>"One" and "Ones" are no longer Reserved<-!>
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The special words "one" and "ones" (or the words you define in these
<:f200,QCourier New,>specialWords<:f> slots) are no longer reserved, so you can use them as ordinary vocabulary words. The parser now treats the words as having their special meanings only in the contexts where they're needed (in particular, they'll have t
he special meaning in responses to disambiguation questions, so that the player can respond to a disambiguation question with a phrase such as "the red one").
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>"abort"<-!><+!> within a Daemon or Fuse<-!>
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>You can now use the <:f200,QCourier New,>abort<:f> statement within a daemon or fuse, and it will work as expected, by terminating the current routine and skipping any remaining fuses or daemons on this turn. In past versions,
<:f200,QCourier New,>abort<:f> was not allowed in a fuse or daemon.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The parser now accepts sentences in the format VERB PREP IOBJ DOBJ. This construction is intended mostly for use in games written in non-English languages that use this sentence format, since it's not a common format for English sentences. Refer to the se
ction on verb templates (page <:X3,-16384;PageRef VerbTemplates>85<:X~3,-16384;PageRef VerbTemplates>) for details of how this sentence format is treated.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>In past versions of TADS, when the player entered a sentence in the format VERB IOBJ DOBJ, the parser used "to" as the preposition; there was no way to change this. You can now specify the preposition to use for sentences in this format by specifying the p
reposition object as the value of the property <:f200,QCourier New,>nilPrep<:f> in the
<:f200,QCourier New,>deepverb<:f> object for the verb. This new property is discussed in the section on verb templates (page
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>TADS users who are also C programmers often find the substantial similarity between TADS and C to be convenient, but also find the slight differences to be a source of confusion when switching between the two languages. TADS now offers the option to use C-
style operators.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>First, we've added the remaining C operators to the TADS language:
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a % b<:f,QCourier,> <:f>Returns the remainder of dividing
<:f200,QCourier New,>a<:f> by <:f200,QCourier New,>b<:f>
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a %= b <:f>Assigns <:f200,QCourier New,>(a % b)<:f> to
<:f200,QCourier New,>a<:f>
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a != b <:f>Equivalent to <:f200,QCourier New,>(a <<<;> b)<:f>
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>!a <:f>Equivalent to <:f200,QCourier New,>(not a)<:f>
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a & b<:f> Bitwise AND
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a &= b<:f> sets <:f200,QCourier New,>a<:f> to
<:f200,QCourier New,>(a & b)<:f>
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a | b<:f> bitwise OR
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a |= b<:f> sets <:f200,QCourier New,>a<:f> to
<:f200,QCourier New,>(a | b)<:f>
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a && b<:f> equivalent to <:f200,QCourier New,>(a and b)<:f>
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a || b<:f> equivalent to <:f200,QCourier New,>(a or b)<:f>
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a ^ b<:f> bitwise XOR of <:f200,QCourier New,>a<:f> and
<:f200,QCourier New,>b<:f>
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a ^= b<:f> sets <:f200,QCourier New,>a<:f> to
<:f200,QCourier New,>(a ^ b)<:f>
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>~a<:f> bitwise negation of <:f200,QCourier New,>a<:f>
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a <<<< b<:f> <:f200,QCourier New,>a<:f> shifted left by
<:f200,QCourier New,>b<:f> bits
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a <<<<= b<:f> sets <:f200,QCourier New,>a<:f> to
<:f200,QCourier New,>(a <<<< b)<:f>
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a <;><;> b <:f200,QCourier New,>a<:f> shifted right by
<:f200,QCourier New,>b<:f> bits
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>a <;><;>= b<:f> sets <:f200,QCourier New,>a<:f> to
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Some of these operators, such as <:f200,QCourier New,>!<:f>, <:f200,QCourier New,>&&<:f>, and
<:f200,QCourier New,>||<:f>, are merely synonyms for existing operators. The "bitwise" operators act on numeric values rather than logical values; they treat their operands as bit vectors, and apply the operation to each bit of the numbers. For example,
<:f200,QCourier New,>3 & 2<:f> has the value 2, since the bit patterns are "011" and "010," respectively. The bit-shift operations are equivalent to multiplying or dividing by a power of 2:
<:f200,QCourier New,>1 <<<< 5<:f> has the value 32, since it's equivalent to multiplying 1 by 2 raised to the 5th power.
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>In addition, TADS now has a mode which uses the C-style assignment operator. Normally, the TADS assignment operator is
<:f200,QCourier New,>:=<:f>, and the equality operator is <:f200,QCourier New,>=<:f>. In C, these operators are
<:f200,QCourier New,>=<:f> and <:f200,QCourier New,>==<:f> respectively. You can now tell TADS to use the C-style operators instead of the TADS version. By default, TADS still uses its own version of the operators. There are two ways to switch into C-sty
le operator mode: by using a command-line option, or by using a new
<:f200,QCourier New,>#pragma<:f> compiler directive in your source code.
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>To compile an entire game in C mode, use the <:f200,QCourier New,>-C+<:f> command line option (Macintosh users will find a menu item for C-style operators under the "Options" menu; check this item to enable C operators, and uncheck it to use standard TADS o
perators). Using the <:f200,QCourier New,>-C+<:f> compiler option enables C operator mode for the entire game's source code. (The
<:f200,QCourier New,>-C-<:f> option explicitly turns off C operator mode. This is the default mode.)
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>To specify that a particular file is to be compiled in C mode, you can use the new directive
<:f200,QCourier New,>#pragma C+<:f>. The similar directive <:f200,QCourier New,>#pragma C-<:f> specifies that TADS operator mode is to be used. These directives can appear anywhere in a source file (outside of comments and strings); they must be alone on
the line, and must not be preceded by any whitespace on the line.
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>A <:f200,QCourier New,>#pragma<:f> setting affects only the current source file, and any files it includes. The header files included with TADS (adv.t and std.t) both use TADS operators, so they explicitly specify
<:f200,QCourier New,>#pragma C-<:f>; because these directives are limited to the header files, you can freely include adv.t from a file that uses C operator mode without having to worry about setting the mode to or from TADS mode. Simply
<:f200,QCourier New,>#include <<adv.t<;><:f> exactly as you did before--even if your source file uses C mode, adv.t will compile correctly, because it sets the operator mode back to TADS for its own contents, and TADS automatically restores the enclosing fi
le's mode at the end of adv.t.
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that the C-style operator mode setting affects only the assignment and equality operators. You can use all of the new C operators (such as the new bitwise operators) in either mode--all of these symbols were invalid in previous versions of TADS, so th
ere's no danger that they'll be misinterpreted for old games.
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>When the compiler is using C-style assignment operators, it issues a new warning, "possibly incorrect assignment," whenever it finds a statement in this format:
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>While this statement is legal, with C-style operators it has the effect of assigning the value 1 to
<:f200,QCourier New,>a<:f>; since the value of an assignment is the value assigned, this
<:f200,QCourier New,>if<:f> will always succeed. It's a common error for C programmers (even highly experienced ones) to write this type of statement when they really want to compare the values; we originally chose to use "<:f200,QCourier New,>:=<:f>" as t
he assignment operator in TADS to reduce the likelihood of this type of error. Now that TADS can be switched to C syntax for assignments and comparisons, we've added the "possibly incorrect assignment" warning to help catch these; the compiler will flag as
signments made in <:f200,QCourier New,>if<:f>, <:f200,QCourier New,>while<:f>, and
<:f200,QCourier New,>do<:f> statements, and in the condition clause of
<:f200,QCourier New,>for<:f> statements. To suppress this warning, you can explicitly test the value of the assignment like this:
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>There are a couple of minor complications with the new operators.
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>First, the <:f200,QCourier New,><;><;><:f> operator can't be used in an expression embedded in a string with the
<:f200,QCourier New,><<<< <;><;><:f> construct, because it would be taken for the
<:f200,QCourier New,><;><;><:f> that terminates the embedded expression. Even adding parentheses won't help, because the compiler recognizes the
<:f200,QCourier New,><<<< <;><;><:f> construct before it looks at any expression in progress. So, this type of code won't work:
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Second, the <:f200,QCourier New,>&<:f> operator now has a binary interpretation in addition to its unary interpretation. For the most part, this won't create any confusion, but there's one situation in which it might: in lists. You might have lists in yo
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>In past versions, since the <:f200,QCourier New,>&<:f> operator could only be a unary operator, this construct was unambiguous; however, now that
<:f200,QCourier New,>&<:f> can be a binary operator, this could be interpreted either as three expressions involving unary
<:f200,QCourier New,>&<:f> operators, or as a single expression involving one unary
<:f200,QCourier New,>&<:f> operator and two binary <:f200,QCourier New,>&<:f> operators.
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>For compatibility with past versions, TADS will interpret the <:f200,QCourier New,>&<:f> operators as
<+">unary<-"> operators. When it finds this construct, though, it will warn you that it is ambiguous. (The new warning is TADS-357, "operator '&' interpreted as unary in list.) You can suppress this warning in one of two ways. First, you can render the
list unambiguous. To do this, use a comma between each pair of list elements:
<:s><:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Note that if you actually want the binary interpretation, you should simply enclose the expression in parentheses:
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The other way you can suppress this message is with the new <:f200,QCourier New,>-v-abin<:f> compiler option, which tells the compiler not to generate the warning. The compiler still interprets the operator the same way when you specify
<:f200,QCourier New,>-v-abin<:f>--it just doesn't tell you about it.
<:I0,432,0,0><:S+273><:R1,13,1,1602,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>Note that TADS will treat <+">any<-"></`>operator which has both a unary and binary interpretation as a unary operator when it finds it within a list, and will generate the TADS-357 warning. For the
<:f200,QCourier New,>-<:f> operator, this is a change from past versions, which used the binary interpretation when in a list. We don't anticipate that this will be a compatibility problem, because the old binary interpretation was almost never desirable,
and we think users avoided it; however, if you have an older game, you may wish to compile without the
<:f200,QCourier New,>-v-abin<:f> option at least once, and check any lines where the TADS-357 warning is generated for
<:f200,QCourier New,>-<:f> or <:f200,QCourier New,>+<:f> operators, to determine if your game's behavior will change with the new version. Any TADS-357 warnings generated for the
<:f200,QCourier New,>&<:f> operator can be safely ignored for a game written with a previous version of TADS.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>TADS now lets you define preprocessor symbols. The <:f200,QCourier New,>#define<:f> directive creates a preprocessor symbol definition:
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>#define TEST "This is a test!"<:f>
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>This defines the symbol <:f200,QCourier New,>TEST<:f>, and specifies that this symbol is to be replaced by the text
<:f200,QCourier New,>"This is a test!"<:f> whenever it appears (outside of strings or comments) in your source code. Note that the definition of a symbol need not be a string--the entire text of the rest of the line is assigned to the symbol.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>You can use a preprocessor symbol that you've defined simply by putting the symbol in your code:
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>When the compiler encounters the preprocessor symbol, it replaces the symbol with its definition, so the compiler treats this the same as:
<:s><:I0,432,0,0><:S+273><:R1,15,1,796,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "This is a test!";
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>You can delete a preprocessor symbol that you've defined using the
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>The compiler automatically defines a number of preprocessor symbol:
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><:f200,QCourier New,>__TADS_VERSION_MAJOR<:f> is defined as the major version number of the current compiler. (Note that this symbol starts with
<+">two<-"></`>underscore characters, as do most of the symbols that the compiler defines for you.) Currently, this is defined as 2.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>__TADS_VERSION_MINOR<:f> is the minor version number, currently 2.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624><:f200,QCourier New,>__TADS_SYSTEM_NAME<:f> is defined as a single-quoted string giving the name of the current system. For DOS systems, this is
<:f200,QCourier New,>'MSDOS'<:f>; for Macintosh systems, this is <:f200,QCourier New,>'Macintosh'<:f>. TADS also defines the value of this symbol as a symbol itself--on MSDOS systems, the compiler defines the symbol
<:f200,QCourier New,>MSDOS<:f>, and on Macintosh systems, the compiler defines
<:f200,QCourier New,>Macintosh<:f>. (The value of the system name symbol is simply 1; it's purpose is to allow for conditional compilation, so the value isn't important.)
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624><:f200,QCourier New,>__DEBUG<:f> is defined if the game is being compiled for debugging (with the
<:f200,QCourier New,>-ds<:f> command line option). By testing this symbol with
<:f200,QCourier New,>#ifdef<:f>, you can easily include parts of your game (such as special "magic" verbs that you use for debugging) only in testing versions of your game, without having to worry about removing them manually when producing the final versio
n of the game for players. The value of this symbol is 1 if it's defined; the purpose of this symbol is to allow for conditional compilation, so its value isn't important.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><:f200,QCourier New,>__DATE__<:f> is defined as a single-quoted string giving the date when the current compilation began, in the format
<:f200,QCourier New,>'Jan 01 1994'<:f>.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><:f200,QCourier New,>__TIME__<:f> is defined as a single-quoted string giving the time when the current compilation began, in the 24-hour format
<:f200,QCourier New,>'01:23:45'<:f>. The time isn't updated during the course of a compilation--it's always the time when compilation began.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><:f200,QCourier New,>__FILE__<:f> is defined as a single-quoted string giving the name of the current source file being compiled.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><:f200,QCourier New,>__LINE__<:f> is defined as a number giving the line number currently being compiled.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>You can define symbols from the compiler command line. The new -D option lets you specify a symbol to define, and optionally a value. Specify the symbol, then an equals sign, then the value; if you omit the equals sign, the default value is 1. For exampl
e, to define the symbol DEMO from the command line, you could use this command:
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>You can also specifically delete preprocessor symbols that the compiler defines (other than
<:f200,QCourier New,>__FILE__<:f> or <:f200,QCourier New,>__LINE__<:f>). You can also undefine any symbols defined earlier on the command line with
<:f200,QCourier New,>-D<:f> options, which may be useful if you're using a configuration file that defines certain symbol. To undefine a symbol, use the -U option:
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>If the symbol <:f200,QCourier New,>DEMO<:f> was defined earlier on the command line, the definition is deleted.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The Macintosh compiler has a new preprocessor options dialog that you can access from the "Options" menu. You can use this dialog to enter symbols to define; in the text box, simply list the symbols (one per line) that you wish to define. If you want to a
ssign values to these symbols, use an equals sign, followed by the value. Another text box in the same dialog lets you list pre-defined symbols that you want to delete; simply list the symbols to be deleted, one per line.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>You can test for the existence of a preprocessor symbol with <:f200,QCourier New,>#ifdef<:f> ("if defined") and you can test to see if a preprocessor symbol is
<+">undefined<-"></`>with the <:f200,QCourier New,>#ifndef<:f> ("if
<+">not<-"></`>defined") directive. These directives let you conditionally include code in your program, depending on whether or not a symbol is defined. For example:
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>#ifdef TEST
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The code between the <:f200,QCourier New,>#ifdef<:f> and the <:f200,QCourier New,>#endif<:f> is included only if the preprocessor symbol
<:f200,QCourier New,>TEST<:f> is defined. There's also a <:f200,QCourier New,>#else<:f> directive, which lets you include a block of lines if the most recent condition failed.
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>Conditional compilation is particularly useful with the symbols you define from the command line with the
<:f200,QCourier New,>-D<:f> option, since it allows you to write your game in such a way that certain features are enabled when you use a particular set of
<:f200,QCourier New,>-D<:f> options. This allows you to use a single set of source files, but produce a variety of different .GAM files. For example, if you want to be able to generate a subset of your game as a demo, you could use conditional compilation
to include or discard sections of the game depending on whether you're compiling the demo or the full game. Similarly, you could use conditional compilation to include certain features only when you're compiling a debugging version of your game; note that
the compiler makes this even easier, because it defines the symbol
<:f200,QCourier New,>__DEBUG<:f> when you're compiling with debugging symbols.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>We've also added the <:f200,QCourier New,>#error<:f> directive. This directive lets you generate an error from within your game. Any text following the
<:f200,QCourier New,>#error<:f> on the line is displayed to the user as the text of the error message. For example:
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>#ifndef TEST
<:s><:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>#error TEST is not defined!
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>The output formatter now recognizes two new escape sequences.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>The first is "<:f200,QCourier New,>\-<:f>" (a backslash followed by a hyphen), and was added in version 2.1. This sequence tells the output formatter to pass the following two bytes as-is, without any interpretation. This is useful for multi-byte characte
r sets (such as on a Japanese-localized Macintosh), where a single character may be represented by two bytes. For the most part, you can freely mix single- and double-byte characters within text strings without any special work. However, some double-byte
characters contain the ASCII code for a backslash as one of their two bytes; in these cases, the output formatter incorrectly interprets the byte whose code is "<:f200,QCourier New,>\<:f>" as introducing an escape sequence. By preceding such characters wit
h "<:f200,QCourier New,>\-<:f>", you can prevent the parser from interpreting the byte with the backslash code as an escape sequence, so the character will be displayed correctly.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The second new escape sequence is "<:f200,QCourier New,>\v<:f>" (a backslash followed by the small letter "v"). This sequence is the opposite of "<:f200,QCourier New,>\^<:f>" (a backslash followed by a circumflex). Whereas "<:f200,QCourier New,>\^<:f>" co
nverts the next character displayed to a capital letter, "<:f200,QCourier New,>\v<:f>" converts the next character to a small letter. Displaying "<:f200,QCourier New,>\v<:f>" is equivalent to calling the
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>TADS now has support for reading and writing files from within your game program. This new feature is intended to let you save information independently of the game-saving mechanism, which allows you to transfer information between sessions of a game, or e
ven between two different games.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Operations on files are all performed through a <+">file handle<-">. This is a special value, generated by TADS, that you use to refer to a file. TADS creates a file handle when you
<+">open<-"> a file; once you've opened a file and obtained its file handle, you can read and write the file. Once you're done with the file, you close the file, which deletes the file handle.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>To open a file, use the <:f200,QCourier New,>fopen()<:f> function. This function takes two arguments: a (single-quoted) string giving the name of the file to open, using local file system conventions, and a "mode." The mode argument is one of these single
-quoted string values:
<:I0,360,0,0><:R><:#273,6624>
<:I0,360,1062,342><:R1,12,1,1062,1,1440,1,2160,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>'r'<:f> open file for reading; file must already exist
<:I0,360,1062,342><:R1,12,1,1062,1,1440,1,2160,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><:f200,QCourier New,>'r+'<:f> open file for reading and writing; the file is created if it doesn't already exist
<:I0,360,1062,342><:R1,12,1,1062,1,1440,1,2160,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>'w'<:f> create a new file for writing; the file is deleted if it already exists
<:I0,360,1062,342><:R1,12,1,1062,1,1440,1,2160,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><:f200,QCourier New,>'w+'<:f> create a new file for reading and writing; the file is deleted if it already exists
<:I0,360,0,0><:R><:#819,6624>For maximum portability, you should avoid using volume names, directories, folders, or other path information in filenames, because any such information might be specific to your computer.
<:I0,360,0,0><:#1638,6624>The return value of <:f200,QCourier New,>fopen()<:f> is a file handle; you must save the file handle so you can use it later to perform operations on the file. If the operation fails, and the file cannot be opened as requested,
<:f200,QCourier New,>fopen()<:f> returns <:f200,QCourier New,>nil<:f>. Opening a file could fail for a number of reasons; for example, if you attempt to open a non-existent file with mode
<:f200,QCourier New,>'r'<:f>, <:f200,QCourier New,>fopen()<:f> will return
<:f200,QCourier New,>nil<:f>, because this mode requires that the file already exists.
<:I0,360,0,0><:#273,6624>This example opens a new file called TEST.OUT for writing:
<:I0,360,0,0><:#1092,6624>Once you've closed a file, the file handle is no longer valid; TADS may re-use the same file handle on a subsequent
<:f200,QCourier New,>fopen()<:f> call. Note that the TADS runtime allows only a limited number of files (currently 10) to be open simultaneously, so you should close a file when you're done with it.
<:I0,360,0,0><:#1638,6624>To write to a file, use <:f200,QCourier New,>fwrite()<:f>. This function takes a file handle, and a value to write; the value can be a string, a number, or
<:f200,QCourier New,>true<:f>. The value can't be <:f200,QCourier New,>nil<:f> (this is because the
<:f200,QCourier New,>fread()<:f> function returns nil to indicate failure; if you could write
<:f200,QCourier New,>nil<:f> to a file, there would be no way to distinguish reading a valid
<:f200,QCourier New,>nil<:f> from an error condition). fwrite() stores the value, along with information on its type.
<:I0,360,0,0><:#546,6624>The <:f200,QCourier New,>fwrite()<:f> function returns <:f200,QCourier New,>nil<:f> on success,
<:f200,QCourier New,>true<:f> on failure. If the function returns
<:f200,QCourier New,>true<:f>, it usually means that the disk is full.
<:I0,360,0,0><:#1638,6624>If the file is open for reading, you can read from the file with the
<:f200,QCourier New,>fread()<:f> function. This function takes a file handle, and it returns a value it reads from the file. The value returned is of the same type as the value originally written at this position in the file with
<:f200,QCourier New,>fwrite()<:f>. If this function returns <:f200,QCourier New,>nil<:f>, it indicates that an error occurred; this usually means that no more information is in the file (which is the case once you've read to the end of the file).
<:I0,360,0,0><:#273,6624>You can get the current byte position in the file with the <:f200,QCourier New,>ftell()<:f> function:
<:I0,360,0,0><:#273,6624>
<:I0,360,0,0><:#273,6624><:f200,QCourier New,>"The current seek position is <<<< ftell(fnum) <;><;>. ";<:f>
<:I0,360,0,0><:#273,6624>
<:I0,360,0,0><:#546,6624>The <:f200,QCourier New,>ftell()<:f> function returns a number giving the byte position that will be read or written by the next file operation.
<:I0,360,0,0><:#819,6624>You can set the file position with <:f200,QCourier New,>fseek()<:f> and
<:f200,QCourier New,>fseekeof()<:f>. The <:f200,QCourier New,>fseek()<:f> function moves the file position to a particular byte position, relative to the beginning of the file. For example, this seeks to the very beginning of a file:
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that you must be careful with <:f200,QCourier New,>fseek()<:f>. You should only seek to positions that you obtained with the
<:f200,QCourier New,>ftell()<:f> function; other positions may be in the middle of a string or a number in the file, so seeking to an arbitrary location and writing could render the file unusable by partially overwriting existing data.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Note that the TADS file operations are not designed as general-purpose file system operations; in particular, these new functions don't have any provisions for creating or reading formatted files, or for exchanging information with programs other than TADS
games. TADS reads and writes files in its own binary format, which is portable across platforms--you can take a binary file written on DOS, and read it on the Macintosh; however, the TADS format isn't designed to be interchanged with other programs, or eve
n to produce simple text files that can be viewed or edited by a user.
@Header@<:I0,0,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#283,6624>New and Improved Built-In Functions
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Adds the <+">word<-"> (a single-quoted string value) to the object as the given part of speech. The
<+">prop<-"></`>parameter can be <:f200,QCourier New,>noun<:f>, <:f200,QCourier New,>adjective<:f>,
<:f200,QCourier New,>plural<:f>, <:f200,QCourier New,>verb<:f>, <:f200,QCourier New,>article<:f>, or
<:f200,QCourier New,>preposition<:f>. You can add words to any object, including objects defined statically in your game, as well as objects created dynamically at run-time.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>For examples of using this function, see the section on Dynamic Vocabulary (page
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Clears the screen. Note that this function may have no effect on some platforms; for example, when the DOS runtime is operating in plain ASCII mode,
<:f200,QCourier New,>clearscreen()<:f> will have no effect.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>This new form of <:f200,QCourier New,>debugTrace<:f> lets you turn a new player command parser diagnostic mode on and off. If
<+">flag<-"> is <:f200,QCourier New,>true<:f>, this function activates the new diagnostic mode; if
<+">flag<-"> is <:f200,QCourier New,>nil<:f>, it turns the diagnostic mode off.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>When the new diagnostic mode is active, the parser generates a series of progress messages as it analyzes the player's command. These messages provide information on how the parser interprets the words in the command. When first reading a sentence, the pa
rser displays all possible parts of speech for each word. As the parser further analyzes the sentence, it displays information on each noun phrase: the words involved, the part of speech that the parser uses for each word in the noun phrase (when a word c
an be used as multiple parts of speech, the parser chooses one part of speech as it reads the noun phrase), and the objects that match the words in the noun phrase.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The parser diagnostic mode may help you track down problems in which the parser refuses to recognize certain noun phrases that you would expect to be valid. Since the parser chooses among ambiguous interpretations of words, it's frequently helpful to under
stand exactly how the parser is interpreting your commands; this new debugging mode should make it easier to gain this understanding.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>This new mode is available in the standard runtime as well as the debugger, so
<:f200,QCourier New,>debugTrace(1,<:f> <+">flag<:f200,QCourier New,><-">)<:f>always succeeds. The function returns no value.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>The original <:f200,QCourier New,>debugTrace()<:f> function still works as it always has.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Deletes the <+">word<-"> (a single-quoted string value) from the object's vocabulary for the given part of speech. The
<+">prop<-"></`>parameter can be <:f200,QCourier New,>noun<:f>, <:f200,QCourier New,>adjective<:f>,
<:f200,QCourier New,>plural<:f>, <:f200,QCourier New,>verb<:f>, <:f200,QCourier New,>article<:f>, or
<:f200,QCourier New,>preposition<:f>. You can delete words from any object, including objects defined statically in your game, as well as objects created dynamically at run-time. Furthermore, you can delete words that were added dynamically, as well as wo
rds that were statically defined in your game.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>For examples of using this function, see the section on Dynamic Vocabulary (page
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Returns the first superclass of the given object. Returns <:f200,QCourier New,>nil<:f> if the object has no superclass (which will only be the case if the object was defined as being of type
<:f200,QCourier New,>object<:f>).
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>This function is provided primarily to facilitate handling equivalent objects. In conjunction with the
<:f200,QCourier New,>isEquivalent<:f> property, this function lets you determine if two objects are indistinguishable from one another. If two objects have the same immediate superclass, and they both have the
<:f200,QCourier New,>isEquivalent<:f> property set to <:f200,QCourier New,>true<:f>, the two objects are equivalent.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Closes the file indicated by <+">filehandle<-">. Once the file is closed, no further operations on
<:I0,432,1062,342><:R1,12,1,1062,1,1440,1,2160,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>'r'<:f> open file for reading; file must already exist
<:I0,432,1062,342><:R1,12,1,1062,1,1440,1,2160,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><:f200,QCourier New,>'r+'<:f> open file for reading and writing; the file is created if it doesn't already exist
<:I0,432,1062,342><:R1,12,1,1062,1,1440,1,2160,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>'w'<:f> create a new file for writing; the file is deleted if it already exists
<:I0,432,1062,342><:R1,12,1,1062,1,1440,1,2160,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><:f200,QCourier New,>'w+'<:f> create a new file for reading and writing; the file is deleted if it already exists
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The function returns a file handle that is used in subsequent file operations (<:f200,QCourier New,>fwrite()<:f>,
<:f200,QCourier New,>fread()<:f>, <:f200,QCourier New,>fclose()<:f>, and the like) to refer to the open file.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If the operation fails, <:f200,QCourier New,>fopen()<:f> returns <:f200,QCourier New,>nil<:f>. This function can fail for a number of reasons; for example, if you attempt to open a file that doesn't exist with mode
<:f200,QCourier New,>'r'<:f>, the operation will fail because this mode can only be used to open an existing file.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Reads the next data item from the file and returns its value. The value will be of the same type as that originally written at the current position in the file with
<:f200,QCourier New,>fwrite()<:f>. If an error occurs, this function returns
<:f200,QCourier New,>nil<:f>; this usually indicates that you are attempting to read past the end of the file.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Seeks to a byte position in the file. The <+">byteposition<-"> value should be a value previously returned by
<:f200,QCourier New,>ftell()<:f>, since other values may not correspond to a value in the file.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>Positions the file at its end.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Returns the current seek position in the file, given as a number of bytes from the beginning of the file.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Writes the given value to the file. The <+">value<-"></`>argument must be a number, a single-quoted string, or
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>This function returns a list of single-quoted strings giving the vocabulary words defined for the given part of speech for the specified object. The
<+">prop<-"></`>parameter can be <:f200,QCourier New,>noun<:f>, <:f200,QCourier New,>adjective<:f>,
<:f200,QCourier New,>plural<:f>, <:f200,QCourier New,>verb<:f>, <:f200,QCourier New,>article<:f>, or
<:f200,QCourier New,>preposition<:f>.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>For examples of using this function, see the section on Dynamic Vocabulary (page
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The new function <:f200,QCourier New,>getfuse(<:f><+">funcptr, parm<:f200,QCourier New,><-">)<:f> lets you determine if the indicated fuse is still active, and if so, how many turns are left until it is activated. If the fuse is not active (it has already
fired, or it has been removed with a call to r<:f200,QCourier New,>emfuse<:f>, or it was simply never set), the function returns
<:f200,QCourier New,>nil<:f>. Otherwise, it returns the number of turns before the fuse is activated.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>This form of <:f200,QCourier New,>getfuse()<:f> lets you check on a fuse set with the
<:f200,QCourier New,>notify()<:f> function. If the fuse is not active, the function returns
<:f200,QCourier New,>nil<:f>, otherwise it returns the number of turns before the fuse is activated.
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Returns the current system clock time. The time is returned as a list of numeric values for easy processing. The list elements are:
<+C><:s><:I0,432,0,0><:S+273><:R1,14,1,72,1,882,1,1872,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>1] year calendar year (e.g., 1992)
<+C><:I0,432,0,0><:S+273><:R1,14,1,72,1,882,1,1872,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>2] month month number (1 for January, 2 for February, etc.)
<+C><:I0,432,0,0><:S+273><:R1,14,1,72,1,882,1,1872,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>3] day day of the month (1 for the first day)
<+C><:s><:I0,432,0,0><:S+273><:R1,14,1,72,1,882,1,1872,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>4] weekday day of the week (1 for Sunday, 2 for Monday, etc.)
<+C><:I0,432,0,0><:S+273><:R1,14,1,72,1,882,1,1872,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>5] year day day of the year (1 for January 1)
<+C><:I0,432,0,0><:S+273><:R1,14,1,72,1,882,1,1872,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>6] hour hour of the day on a 24-hour clock (0 is midnight)
<+C><:I0,432,0,0><:S+273><:R1,14,1,72,1,882,1,1872,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>7] minute minute within the hour (0 to 59)
<+C><:I0,432,0,0><:S+273><:R1,14,1,72,1,882,1,1872,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>8] second second within the minute (0 to 59)
<+C><:s><:I0,432,0,0><:S+273><:R1,14,1,72,1,882,1,1872,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><[>9] elapsed seconds since January 1, 1970, 00:00:00 GMT
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>This function has been extended to allow you to run a series of turns all at once. You can now specify a numeric argument to
<:f200,QCourier New,>incturn()<:f>; the argument gives the number of turns that should pass. An argument of 1 is equivalent to calling
<:f200,QCourier New,>incturn()<:f> with no arguments.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>When an argument higher than 1 is specified, the function runs all of the fuses that are set to turn down within the number of turns specified, but not after that number of turns. Note that the normal
<:f200,QCourier New,>incturn()<:f> doesn't actually execute any fuses, but simply burns all fuses down by one turn.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>For example, if you call <:f200,QCourier New,>incturn(2)<:f>, the system will first run any fuses that are set to burn down after 1 turn, then will shorten all remaining fuses by one turn. Similarly,
<:f200,QCourier New,>incturn(3)<:f> first runs any fuses that are set to burn down after 1 turn, then runs any fuses set to burn down after 2 turns, then shortens any remaining fuses by 2 turns.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Fuses set with <:f200,QCourier New,>setfuse()<:f> and <:f200,QCourier New,>notify()<:f> are both affected by this routine. Note that this function has no effect on daemons.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>Reads a single keystroke from the keyboard, and returns a string consisting of the character read.
<:f200,QCourier New,>inputkey()<:f> takes no arguments. When called, the function first flushes any pending output text, then pauses the game until the player hits a key. Once a key is hit, a string containing the character is returned. Note that this fu
nction does <+">not<-"> provide a portable mechanism for reading non-standard keys, such as cursor arrow keys and function keys. If the user hits a non-standard key, the return value is the representation of the key on the operating system in use. To ensu
re portability, you should use this function only with standard keys (alphabetic, numeric, and punctuation mark keys). Note that you will encounter no portability problems if you simply ignore the return value and use
<:f200,QCourier New,>inputkey()<:f> only to pause and wait for a key.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Note that <:f200,QCourier New,>inputkey()<:f> takes its input directly from the keyboard. It does
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Returns the intersection of two lists--that is, the list of items in both of the two lists provided as arguments. For example:
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>yields the list <:f200,QCourier New,><[>2 4 6]<:f>.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Note that the behavior for lists with repeated items is not fully defined with respect to the number of each repeated item that will appear in the result list. In the current implementation, the number of repeated items that is present in the
<+">shorter<-"></`>of the two source lists will be the number that appears in the result list; however, this behavior may change in the future, so you should try not to depend on it.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>This function is the opposite of <:f200,QCourier New,>caps()<:f>--it specifies that the next character displayed will be converted to lower case. Note that you can use the new escape sequence "<:f200,QCourier New,>\v<:f>" to achieve the same effect.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Note that calls to <:f200,QCourier New,>caps()<:f> and <:f200,QCourier New,>nocaps()<:f> override one another; if you call
<:f200,QCourier New,>caps()<:f>, and then immediately call <:f200,QCourier New,>nocaps()<:f>, the next character displayed will be lower-case--the call to
<:f200,QCourier New,>caps()<:f> is forgotten after the call to <:f200,QCourier New,>nocaps()<:f>.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Provides a list of the actual words the user typed to refer to an object used in the current command. The argument
<+">num<-"> specifies which object you're interested in: 1 for the direct object, or 2 for the indirect object. The return value is a list of strings; the strings are the words used in the command (converted to lower case, stripped of any spaces or punctu
ation). If a special word such as "it," "them," or "all" was used to specify the object, the list will have a single element, which is the special word used.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>For example, if the player types "take all," then <:f200,QCourier New,>objwords(1)<:f> will return
<:f200,QCourier New,><[>'all']<:f> and <:f200,QCourier New,>objwords<[>2]<:f> will return
<:f200,QCourier New,><[>]<:f>. Note that <:f200,QCourier New,>objwords(1)<:f> will return
<:f200,QCourier New,><[>'all']<:f> even if the player typed a variation on "all," such as "take everything" or "take all but the book."
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>If the player types "put all in red box," the <:f200,QCourier New,>objwords(1)<:f> returns
<:f200,QCourier New,><[>'all']<:f> and <:f200,QCourier New,>objwords(2)<:f> returns
<:f200,QCourier New,><[>'red' 'box']<:f>.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>If the player uses multiple direct objects, the function will return the
<+">current<-"></`>object's words only. For example, if the player types "put blue folder and green book in red box,"
<:f200,QCourier New,>objwords(1)<:f> will return <:f200,QCourier New,><[>'blue' 'folder']<:f> while the first direct object is being processed, and
<:f200,QCourier New,><[>'green' 'book']<:f> while the second object is being processed.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>This function could potentially be useful in such cases as "ask <+">actor<-"> about
<+">object<-">," because it allows you to determine much more precisely what the player is asking about than would otherwise be possible.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>You can call <:f200,QCourier New,>objwords()<:f> during a verb verification or action method (<:f200,QCourier New,>verDo<+"><:f>Verb<-">,
<:f200,QCourier New,>io<+"><:f>Verb<-">), and during a <:f200,QCourier New,>doDefault<:f> method. Note that the return value is slightly different during a
<:f200,QCourier New,>doD<:f><:f200,QCourier New,>efault<:f> method: if the word "all" is used in the command, the function will return the list
<:f200,QCourier New,><[>'A']<:f> rather than <:f200,QCourier New,><[>'all']<:f>, due to the internal order of processing of the word list.
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>objwords(1) words with doDefault
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><-">You can now call <:f200,QCourier New,>objwords(1)<+!><-"><:f>
<-!>from within the <:f200,QCourier New,>doDefault<:f> method, as described above. Until version 2.2, you could call
<:f200,QCourier New,>objwords(1)<:f> only from verb verification and action methods.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>Turns hidden output on or off, simulating the way the parser disambiguates objects. The parameter
<+">flag<-"> is either <:f200,QCourier New,>true<:f> or <:f200,QCourier New,>nil<:f>. When you call
<:f200,QCourier New,>outhide(true)<:f>, the system starts hiding output. Subsequent output is suppressed--it won't be shown to the player. When you call
<:f200,QCourier New,>outhide(nil)<:f>, the system stops hiding output--subsequent output is once again displayed.
<:f200,QCourier New,>outhide(nil)<:f> also returns a value indicating whether any (suppressed) output was generated since the call to
<:f200,QCourier New,>outhide(true)<:f>, which allows you to determine whether any output
<+">would<-"></`>have resulted from the calls made between <:f200,QCourier New,>outhide(true)<:f> and
<:f200,QCourier New,>outhide(nil)<:f>.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>This is the same mechanism used by the parser during disambiguation, so it should
<+">not<-"></`>be called by a <:f200,QCourier New,>verDo<+"><:f>Verb<-"> or
<:f200,QCourier New,>verIo<+"><:f>Verb<-"> method. This function is provided to allow you to make calls to
<:f200,QCourier New,>verDo<+"><:f>Verb<-"> and <:f200,QCourier New,>verIo<+"><:f>Verb<-"> to determine if they will allow a particular verb with an object, just as the parser does.
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>There is no way to recover the text generated while output is being hidden. The only information available is whether any text was generated.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>When you call <:f200,QCourier New,>outhide(true)<:f>, the function returns a status indicator, which is a value that can be used in a subsequent call to
<:f200,QCourier New,>outhide()<:f> to restore output hiding to the state it was in before the
<:f200,QCourier New,>outhide(true)<:f>. This allows you to nest text hiding--you can hide output in a subroutine or method call, without interfering with the routine that called you or any routines you call.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>To use the nested form, save the return value of <:f200,QCourier New,>outhide(true)<:f>, and then use the saved value as the parameter--in place of
<:f200,QCourier New,>nil<:f>--to the subsequent call to <:f200,QCourier New,>outhide()<:f>. The value returned by the second
<:f200,QCourier New,>outhide()<:f> indicates whether any text output occurred
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>"This is some hidden test.";
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>// don't write any text here
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Because <:f200,QCourier New,>outhide(old_stat2)<:f> indicates whether any output occurred during the
<+">nested<-"> <:f200,QCourier New,>outhide(true)<:f>, <:f200,QCourier New,>new_stat2<:f> is
<:f200,QCourier New,>nil<:f>. However, <:f200,QCourier New,>new_stat1<:f> is
<:f200,QCourier New,>true<:f>, since output occurred after the first
<:f200,QCourier New,>outhide(true)<:f>. Consider another sequence:
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>// write no text here
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>"This is some hidden text.";
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>In this case, both <:f200,QCourier New,>new_stat1<:f> and <:f200,QCourier New,>new_stat2<:f> will be true, because hidden output occurred within both nested sections (even though only a single message was displayed, it was within both nested sections).
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>The general form of a nested <:f200,QCourier New,>outhide()<:f> section is:
<+C><:I0,432,0,0><:S+273><:R1,16,1,72,1,818,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> local old_stat;
<+C><:I0,432,0,0><:S+273><:R1,16,1,72,1,818,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> local new_stat;
<+C><:s><:I0,432,0,0><:S+273><:R1,16,1,72,1,818,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> // do whatever you want here
<+C><:s><:I0,432,0,0><:S+273><:R1,16,1,72,1,818,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> // output will be hidden
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The <:f200,QCourier New,>new_stat<:f> will indicate whether any output occurred between the
<:f200,QCourier New,>outhide(true)<:f> and the <:f200,QCourier New,>outhide(old_stat)<:f>. In addition, output hiding will be restored to the same state as it was prior to the
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>rand() is more random<-!>
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The random number generator has been improved. Some people noticed that the old random number generator was producing somewhat less than ideally random results, especially when small upper limits were used. The interface to the new random number generator
is exactly the same as before.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Note that the old random number generator is still used if you don't call
<:f200,QCourier New,>randomize()<:f>. This allows test scripts (which require a fixed sequence of random numbers in order to be repeatable) that were written with older versions of TADS to continue to work unchanged. If you want numbers from the improved
generator, be sure to call <:f200,QCourier New,>randomize()<:f>.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3549,6624>This new form of <:f200,QCourier New,>restart()<:f> lets you specify a function to be called after restarting the game, but before the
<:f200,QCourier New,>init()<:f> function is invoked. This new feature has been added because it would otherwise be impossible to pass any information across a restart operation: the
<:f200,QCourier New,>restart()<:f> function doesn't return, and all game state is reset to its initial state by
<:f200,QCourier New,>restart()<:f>. You can use this new form of the function if you want a restarted game to have different startup behavior than the game has when it's first started. Note that adv.t passes a pointer to the
<:f200,QCourier New,>initRestart<:f> function (defined in adv.t when it invokes
<:f200,QCourier New,>restart()<:f> in response to a "restart" command from the player; the adv.t implementation of
<:f200,QCourier New,>initRestart()<:f> simply sets the flag <:f200,QCourier New,>global.restarting<:f> to
<:f200,QCourier New,>true<:f> to indicate that the game is being restarted rather than first entered. You can
<:f200,QCourier New,>replace<:f> the <:f200,QCourier New,>initRestart<:f> function defined in adv.t if you want to customize the restart behavior.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>The <+">param<-"> value is simply passed as the parameter to the function to be called; this allows you to pass information through the restart. For example, if you start the game with a questionnaire asking the player's name, sex, and age, you could pass
a list containing the player's responses to your restart function, and have the restart function store the information without making the player answer the questionnaire again. The call to
<:f200,QCourier New,>restart()<:f> in adv.t uses <:f200,QCourier New,>global.initRestartParam<:f> as the parameter for the
<:f200,QCourier New,>initRestart<:f> function; so, if you provide your own version of
<:f200,QCourier New,>initRestart<:f>, you can simply store the necessary information in
<:f200,QCourier New,>global.initRestartParam<:f> to ensure that it's passed to your function.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>This special new form of the <:f200,QCourier New,>restore()<:f> function allows you to choose the time during startup that the player's saved game is restored when the player starts your game with a saved game already specified. When you call
<:f200,QCourier New,>restore(nil)<:f>, the system checks to see if a saved game was specified by the player at startup, and if so, immediately restores the game and returns
<:f200,QCourier New,>nil<:f>. If no game was specified, the function returns
<:f200,QCourier New,>true<:f>.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>Current, it's possible for a player to start a game in this manner only on the Macintosh, but the new
<:f200,QCourier New,>restore()<:f> functionality will work correctly on all platforms. On the Macintosh, the operating system allows an application to be started by opening one of the application's documents from the desktop; the application is started, an
d is informed that the user wishes to open the specified file. Saved game files on the Macintosh are associated with the game executable that created them in such a way that the game is executed when a saved game is opened. This is simply a convenience fe
ature on the Mac that allows a player to run a game and restore a saved position in a single operation.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>You can use <:f200,QCourier New,>restore(nil)<:f> in your <:f200,QCourier New,>init<:f> function to choose the point at which the saved game will be restored. If your game has extensive introductory text, you could call
<:f200,QCourier New,>restore(nil)<:f> prior to displaying your introductory text, and then skip the introductory text if the function returns
<:f200,QCourier New,>nil<:f>.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The reason that the system doesn't restore the saved game prior to calling your
<:f200,QCourier New,>init<:f> function is that you may want parts of your
<:f200,QCourier New,>init<:f> function to be invoked regardless of whether a game is going to be restored or not. For example, you may want to display your copyright message, or ask a copy-protection question, even when a saved game is going to be restored
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If you do not make a call to <:f200,QCourier New,>restore(nil)<:f> in your
<:f200,QCourier New,>init<:f> function, TADS will automatically restore the saved game specified by the player immediately
<+">after<-"> your <:f200,QCourier New,>init<:f> function returns. Hence, omitting the call to
<:f200,QCourier New,>restore(nil)<:f> doesn't do any harm; this function is provided to give you greater control.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Runs all of the daemons. This function runs daemons set with <:f200,QCourier New,>setdaemon()<:f> and
<:f200,QCourier New,>notify()<:f>. This function returns no value.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Runs all expired fuses, if any. Returns <:f200,QCourier New,>true<:f> if any fuses were ready to run,
<:f200,QCourier New,>nil<:f> otherwise. This function runs fuses set both with
<:f200,QCourier New,>setfuse()<:f> and with <:f200,QCourier New,>notify()<:f>.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>You can now use <:f200,QCourier New,>nil<:f> as the argument to <:f200,QCourier New,>setit()<:f>. This prevents the player from using "it" in the next command.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>You can now specify which pronoun you want to set. The new optional parameter
<+">num<-"> specifies which pronoun to set: 1 for "him," and 2 for "her." When
<+">num<-"> isn't specified, <:f200,QCourier New,>setit(<:f><+">obj<:f200,QCourier New,><-">)<:f> sets "it" as usual. Note that
<:f200,QCourier New,>nil<:f> can be used as the <+">obj<-"> argument to clear "him" or "her," just as it can with "it."
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>You can now set "them" directly, simply by passing a list of objects (rather than a single object) to
<:f200,QCourier New,>setit()<:f>. Calling <:f200,QCourier New,>setit()<:f> with a list argument has the side effect of clearing "it."
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>This function is similar to <:f200,QCourier New,>incturn(<+"><:f>num<:f200,QCourier New,><-">)<:f>; this function
<+">skips<-"> the given number of turns, which must be at least 1. The difference between
<:f200,QCourier New,>skipturn()<:f> and <:f200,QCourier New,>incturn()<:f> is that
<:f200,QCourier New,>skipturn()<:f> doesn't run any of the fuses that burn down during the turns being skipped--instead, it simply removes them without running them.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Fuses set with <:f200,QCourier New,>setfuse()<:f> and <:f200,QCourier New,>notify()<:f> are both affected by this routine. Note that this function has no effect on daemons.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>This function lets you retrieve information on the <:f200,QCourier New,>doAction<:f> and
<:f200,QCourier New,>ioAction<:f> definitions for the given <:f200,QCourier New,>deepverb<:f> object. This function returns a list giving the verification and actor property pointers for the appropriate verb template. Refer to the section on getting verb
information (page <:X3,-16384;PageRef GettingVerbInfo>9<:X~3,-16384;PageRef GettingVerbInfo>) for details on this function.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Case Insensitivity in Commands<-!>
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Commands are no longer case-sensitive. The command "BP" is now equivalent to "bp."
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>We've added a mechanism that lets you capture a log of all method and function calls, and then inspect the log. This feature can help you determine the exact sequence of calls that TADS itself makes into your game, and also lets you see how your game and l
ower-level classes (such as those from adv.t) interact. Four new command let you control logging (on the Macintosh, these are also accessible from the "Execution" menu):
<:s><:I0,432,792,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>c+ Begins call logging. Any previous call log is cleared, and all subsequent method and function calls and returns will be added to the new call log.
<:s><:I0,432,792,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>cc Clears the current call log.
<:s><:I0,432,792,0><:S+273><:R1,15,1,792,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>c Displays the current call log. Shows all function and method calls after the most recent c+ and up to the current time, or the most recent c-.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The reason that commands are provided to turn call logging on and off is that the logging process can slow down your game's execution substantially. When call logging is activated, the system must do extra work every time a function or method is entered or
exited. You should enable call logging at the point you're about to execute a command that you want to trace, then turn it off when you're finished with the command.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that the call log is limited in capacity. If the log becomes full, the oldest information is discarded to make room for new information. If you leave call logging activated for an extended period of time, information toward the beginning of the log m
ay be lost.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The lines of text displayed in the call log will be indented to show nesting. The functions and method called directly by TADS will not be indented at all; anything called by these functions and methods will be indented one space; and so on. If a function
or method has a return value, it will be indicated in the log (prefixed by "<:f200,QCourier New,>=<;><:f>") at the point where the function or method returns. Each call will show the object and method or function name involved, along with the arguments; t
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The debugger will now take control when a run-time error occurs. The error message will be displayed, and execution will be suspended at the line where the error occurred. When you resume execution, the current turn will be aborted (as though an
<:f200,QCourier New,>abort<:f> statement had been executed).
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>You can now break out of an infinite loop in your game. Hit Ctrl-Break if you're running on a DOS machine, or Command-Period on a Macintosh. The debugger will take control.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Breakpoints in Inherited Methods (2.1)<-!>
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The debugger will now stop at a breakpoint in a method inherited by an object. For example, if you set a breakpoint at
<:f200,QCourier New,>room.lookAround<:f>, execution will stop any time a subclass of
<:f200,QCourier New,>room<:f> executes the inherited <:f200,QCourier New,>lookAround<:f> method. Of course, if a subclass overrides the
<:f200,QCourier New,>lookAround<:f> method, execution will not stop at
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The run-time memory requirements for the debugger have been reduced, which should allow larger games to be debugged on smaller machines (such as DOS machines) without the out-of-memory conditions that some people have experienced with past versions.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>This option sets the warning verbosity level. The default level is 0 (minimum verbosity: suppress warnings which are purely informational or generally do not indicate an actual problem). Other levels are 1 (suppress purely informational messages, but disp
lay warnings even when they generally do not indicate a problem), and 2 (maximum verbosity: display all warnings and informational messages).
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Sets the .GAM file format. The <+">type<-"></`>can be <:f200,QCourier New,>a<:f> for file format "A" (used by TADS versions prior to 2.1),
<:f200,QCourier New,>b<:f> for format "B" (used by versions 2.1 up to but not including 2.2),
<:f200,QCourier New,>c<:f> for format "C" (introduced in version 2.2), or
<:f200,QCourier New,>*<:f> for the most recent version (currently "C"). The default is
<:f200,QCourier New,>-fv*<:f>. You can use this option if you wish to compile your game so that it can be used with an earlier version of the TADS runtime.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Version 2.1 of TADS uses file format "B," which is slightly different from the original file format, and 2.2 uses format "C," which differs slightly from "B." File formats other than "A" will not be accepted by versions of the runtime earlier than 2.1. Th
e version 2.2 runtime is able to read any previous file format.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The changes made in version "B" make the .GAM file much more compressible with archiving utilities. If you use file format "A," your games will not compress very well with programs such as ZIP.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The changes made in version "C" enable the <:f200,QCourier New,>disambigDobjFirst<:f> flag. If you compile with an earlier file format, you will not be allowed to use this flag.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>This option tells the compiler to log all error messages to <+">file<-">. The compiler writes all of the messages generated during compilation to the indicated file; the messages will also be displayed on your screen as usual. The file will be created if
it doesn't exist, and it will be overwritten with the new error log if it already exists.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,>(Note that this is a capital "C.") This is a toggle option that lets you turn C operator mode on and off (see the section on C operators on page
<:X3,-16384;PageRef COperators>20<:X~3,-16384;PageRef COperators>). The default is
<:f200,QCourier New,>-C-<:f>, which enables the standard TADS operators. If you specify
<:f200,QCourier New,>-C+<:f>, TADS will change the assignment operator to "<:f200,QCourier New,>=<:f>" and the equality operator to "<:f200,QCourier New,>==<:f>" to match the C language.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Disables the warning message "operator <+">x<-"> interpreted as unary in list." (TADS-357). If you're compiling a game written with a previous version of TADS, and you get this warning, you may want to use
<:f200,QCourier New,>-v-abin<:f> to disable the warning. This warning is intended to notify you that the
<+">new<-"></`>meaning of the operator is <+">not<-"></`>being used--in other words, TADS is warning you that it's using an interpretation that's compatible with past versions of the compiler. If your game was written for an older version of the system, th
is is exactly what you want, so you probably don't need the warning.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Improved error checking for -m<-!>
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The compiler now checks more carefully to ensure that the memory size settings specified with the various
<:f200,QCourier New,>-m<:f> parameters (in particular, <:f200,QCourier New,>-mg<:f>,
<:f200,QCourier New,>-mp<:f>, <:f200,QCourier New,>-ml<:f>, <:f200,QCourier New,>-ms<:f>, and
<:f200,QCourier New,>-mh<:f>) are valid. These settings must fit within certain limits, which are now enforced more carefully. Previous versions of the compiler responded unpredictably to invalid settings.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>The compiler now lets you turn off case sensitivity. If you don't want to distinguish between upper- and lower-case letters in your symbols, you can use the
<:f200,QCourier New,>-case-<:f> option to turn off the compiler's case sensitivity. By default, the compiler is set to
<:f200,QCourier New,>-case+<:f>, which makes the compiler treat an upper-case letter as distinct from the same letter in lower-case. When the compiler is case-sensitive,
<:f200,QCourier New,>deepverb<:f> and <:f200,QCourier New,>deepVerb<:f> are different symbols. If you would prefer not to keep track of the exact case of the letters in the symbols defined in your game (or in adv.t), you can make the compiler treat upper-
and lower-case letters the same by using <:f200,QCourier New,>-case-<:f>.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Note that adv.t will work either way. All of the references to a particular symbol in adv.t use the same case, so adv.t will work properly with case sensitivity turned on. However, adv.t will also work properly with case sensitivity turned off, because it
doesn't have any symbols that depend on being in a particular case (for example, it doesn't define one symbol called "a" and a distinct symbol called "A"--if it did, these symbols would collide when compiling without case sensitivity).
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Macintosh Compiler no longer adds ".t" Suffix<-!>
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The Macintosh compiler no longer adds a default suffix to input files. In past versions, the compiler added ".t" to the name of a source file if the source file didn't have any periods in its name. While adding a default suffix is convenient on other plat
forms (since it saves the user the trouble of typing the suffix on the command line), it's obviously not desirable on the Macintosh, since the user specifies the file by pointing at it--the full filename is always given, so a suffix shouldn't be added.
@Header@<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#283,6624>Changes to adv.t
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The new class <:f200,QCourier New,>distantItem<:f> has been added. This new class is similar to
<:f200,QCourier New,>fixeditem<:f>, except that it's intended to be used to objects that are not actually part of a room, but are
<+">visible<-"> from the room in the distance. For example, you might use this class for distant mountains visible from a location--the player obviously shouldn't be able to do anything to the mountains except look at it them. A
<:f200,QCourier New,>distantItem<:f> can be inspected, but any other attempts to manipulate the object will receive the response "It's too far away."
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The new <:f200,QCourier New,>scoreStatus(<:f200,QCourier New,><-">points, turns<:f200,QCourier New,>)<:f> function has been added. This new function simply calls
<:f200,QCourier New,>setscore()<:f> with the same arguments. All other calls to
<:f200,QCourier New,>setscore()<:f> in adv.t have been replaced with calls to this new function, which makes it easy to provide a new scoring format, if you wish, simply by using
<:f200,QCourier New,>replace<:f> to substitute your own <:f200,QCourier New,>scoreStatus()<:f> function for the one in adv.t.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Two new properties have been added to the <:f200,QCourier New,>nestedroom<:f> class:
<:f200,QCourier New,>statusPrep<:f>, which displays an appropriate preposition for status line displays while the player is in the nested room; and
<:f200,QCourier New,>outOfPrep<:f>, which displays the correct preposition when leaving the nested room. The default values are "in" for
<:f200,QCourier New,>statusPrep<:f> and "out of" for <:f200,QCourier New,>outOfPrep<:f>. The class
<:f200,QCourier New,>beditem<:f> provides values of "on" and "out of" instead. If you're defining a new subclass of
<:f200,QCourier New,>nestedroom<:f>, you can override these properties to provide the most appropriate messages for the subclass.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>fixeditem and "throw" (2.1)<-!>
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>You can no longer throw a <:f200,QCourier New,>fixeditem<:f> at anything
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>clothingItem: "get out of" (2.1)<-!>
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>You can now "get out of" a piece of clothing; this is equivalent to "take off."
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The various verbs which use the word "look" plus a preposition have been modified to allow "l" in place of "look"; this applies to several verbs, including "look at" (which now accepts "l at" as equivalent), "look on," "look in," "look under," "look around,
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The <:f200,QCourier New,>doDefault<:f> method in <:f200,QCourier New,>takeVerb<:f> has been corrected so that it doesn't return the contents of a closed object. In previous versions of adv.t, "take all from object" would succeed even when the object was cl
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>vehicle manipulation from within (2.1)<-!>
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The <:f200,QCourier New,>vehicle<:f> class has been corrected so that the player cannot generally manipulate the vehicle while occupying it. For example, the player can no longer take a vehicle or put it anywhere while inside it.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>A new function, <:f200,QCourier New,>initRestart(param)<:f>, has been added. This function is used when adv.t calls the
<:f200,QCourier New,>restart()<:f> built-in function (to start the game over from the beginning) in response to a "restart" command. The
<:f200,QCourier New,>initRestart()<:f> in adv.t simply sets the property
<:f200,QCourier New,>global.restarting<:f> to <:f200,QCourier New,>true<:f>. Your game can inspect this flag in your
<:f200,QCourier New,>init<:f> function (or elsewhere) to take a different course of action when restarting a game than when starting up for the first time. The parameter is not used by adv.t implementation of the function, but if you
<:f200,QCourier New,>replace<:f> the <:f200,QCourier New,>initRestart<:f> function defined in adv.t, you might find the parameter useful for passing information through the restart.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>The "restart" verb passes a pointer to the <:f200,QCourier New,>initRestart<:f> function when it calls the
<:f200,QCourier New,>restart()<:f> built-in function. This causes
<:f200,QCourier New,>initRestart<:f> to be invoked after the game has been restarted, but before the system calls
<:f200,QCourier New,>init<:f>. Note that the call to <:f200,QCourier New,>restart()<:f> passes
<:f200,QCourier New,>global.initRestartParam<:f> as the parameter to the
<:f200,QCourier New,>initRestart<:f> function. If you replace <:f200,QCourier New,>initRestart<:f> with your own implementation, and you need to pass some information to this function from the game running before the restart, simply store the necessary inf
ormation in <:f200,QCourier New,>global.initRestartParam<:f> at any time before restarting, and the information will automatically be passed to your
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>We've added the new property <:f200,QCourier New,>pluraldesc<:f> to the class
<:f200,QCourier New,>thing<:f> in adv.t. The definition simply adds an "s" to the end of the sdesc property. This new property is used by
<:f200,QCourier New,>listcont()<:f> when multiple equivalent objects are present in a list; for details, see the information on the changes to
<:f200,QCourier New,>listcont()<:f> described in the section on indistinguishable objects (page
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The <:f200,QCourier New,>listcont<:f> and <:f200,QCourier New,>itemcnt<:f> functions in adv.t have been enhanced to list multiple occurrences of the same indistinguishable item only once, with the number of such items. See the section on indistinguishable
objects (page <:X3,-16384;PageRef Indistinguishables>10<:X~3,-16384;PageRef Indistinguishables>) for more information.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>All of the system verbs in adv.t that use the <:f200,QCourier New,>abort<:f> statement have been modified slightly to make it easier to augment their behavior with the
<:f200,QCourier New,>modify<:f> statement. All of the processing other than the
<:f200,QCourier New,>abort<:f> has been moved out of the <:f200,QCourier New,>do<:f><+">Verb<-"> (or
<:f200,QCourier New,>action<:f>) method, and put into a new method. For example, the
<:f200,QCourier New,>action<:f> method in <:f200,QCourier New,>saveVerb<:f> now looks like this:
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The new method <:f200,QCourier New,>saveGame<:f> in <:f200,QCourier New,>saveVerb<:f> now performs all of the processing that the
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The benefit of this change is that you can modify the <:f200,QCourier New,>saveGame<:f> method, and inherit the original behavior, without having to worry about an
<:f200,QCourier New,>abort<:f> statement interfering with the order of operations. For example:
<:I0,432,0,0><:S+273><:R1,16,1,72,1,785,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> // restore the game<:f><:f200,QCourier New,>, and<:f><:f200,QCourier New,> check for success
<:I0,432,0,0><:S+273><:R1,16,1,72,1,785,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (inherited.restoreGame(actor))
<:s><:I0,432,0,0><:S+273><:R1,16,1,72,1,785,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> // re-randomize the puzzle
<:I0,432,0,0><:S+273><:R1,16,1,72,1,785,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "The carnival hawker flashes a mischievous<:f>
<:I0,432,0,0><:S+273><:R1,16,1,72,1,785,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> smile at you. \"There's no use trying to
<:I0,432,0,0><:S+273><:R1,16,1,72,1,785,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> guess the answer,\" he says. \"I changed<:f>
<:s><:I0,432,0,0><:S+273><:R1,16,1,72,1,785,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> around the shells while you were busy
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The format mask <:f200,QCourier New,>fmtMe<:f> has been added. You can now use "%me%" in messages to refer to the actor. For
<:f200,QCourier New,>basicMe<:f>, <:f200,QCourier New,>fmtMe<:f> is set to the message "me"; for other actors, it's set to the actor's
<:f200,QCourier New,>thedesc<:f>. In adv.t, <:f200,QCourier New,>thing.ldesc<:f> has been changed to use "%me%": "It looks like an ordinary <<<<sdesc<;><;> to %me%." This makes the default sentence somewhat more adaptable if you ask another actor to desc
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>guard, look at the card
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>It looks like an ordinary card to the guard.
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>again, wait, sleep are darkverbs<-!>
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The verbs "again," "wait," and "sleep" are now all <:f200,QCourier New,>darkVerb<:f> subclasses. None of these verbs logically requires any light (in fact, one could argue that "sleep" works better in the dark).
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The <:f200,QCourier New,>specialWords<:f> definition in adv.t now adds "there" as a synonym for "it." This allows commands such as: "Take the box and put the ball in there."
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The <:f200,QCourier New,>showcontcont()<:f> function no longer displays the contents of an object with the
<:f200,QCourier New,>isqsurface<:f> property set to true.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>We added a new class, <:f200,QCourier New,>seethruItem<:f>, which the player can look through. This is intended for objects such as windows or magnifying glasses. If the player looks through the object (with a command such as "look through the window"), t
he object calls its <:f200,QCourier New,>thrudesc<:f> method to display an appropriate description of what the player sees. You should customize this method to display an appropriate message for each
<:f200,QCourier New,>seethruItem<:f> you create; the default method displays "You can't see much through the window," which obviously won't be what you wanted.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The class <:f200,QCourier New,>thing<:f> previously defined a <:f200,QCourier New,>thrudesc<:f> method as described above. To preserve compatibility with any existing games that depended on the presence of this method in
<:f200,QCourier New,>thing<:f>, we left this as it was.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Note that <:f200,QCourier New,>seethruItem<:f> is <+">not<-"></`>the same as
<:f200,QCourier New,>transparentItem<:f>. The class <:f200,QCourier New,>transparentItem<:f> is for objects whose
<+">contents<-"></`>are visible, whereas <:f200,QCourier New,>seethruItem<:f> is for objects that the player can look through. Use
<:f200,QCourier New,>seethruItem<:f> for windows, binoculars, magnifying glasses, and other non-containers. Use
<:f200,QCourier New,>transparentItem<:f> for glass bottles and other transparent containers.
@Header@<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#283,6624>DOS Color Customization (2.1)
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The player can now customize the colors used by the DOS runtime. A small new program, TRCOLOR, lets the player select the colors to use while running a game. The program is self-explanatory: it displays instructions on-screen, and uses the arrow keys to
select colors. The program lets a player customize the colors to use for the main text area, highlighted text, and the status line. Type TRCOLOR at the DOS prompt to run the program.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Once you've selected your color scheme, the TRCOLOR program creates a small file called TRCOLOR.DAT in the current directory. The runtime reads this file at the start of subsequent game sessions.
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Note that you can use multiple TRCOLOR.DAT files, in the same way that you can use multiple CONFIG.TC files. The runtime looks for TRCOLOR.DAT first in the current directory; if no such file exists, the runtime uses the TRCOLOR.DAT in the directory contain
ing TR.EXE. This allows you to set up a separate color scheme for each game you're playing, and in addition set up a default color scheme for games with no color schemes of their own.
@Header@<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#283,6624>Improvements to MAKETRX
<:I0,432,0,0><:S+273><:R1,14,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>We've made a couple of changes to the MAKETRX program (on Macintosh, this program is called the "Executable Game Builder"). First, in version 2.1, we simplified the command line for the DOS version by letting you leave off arguments when MAKETRX is able to
determine a suitable default. Second, in version 2.2, we added the ability to "bind" a set of run-time configuration options into your game executable--both the DOS and Macintosh versions provide this new feature.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>In version 2.1, we improved the user interface of the DOS version of MAKETRX. For compatibility with existing makefiles, the old command line syntax is still allowed; however, you can now omit most of the arguments, and MAKETRX will provide suitable defaul
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>First, you can omit the filename extensions for any of the arguments. The extension assumed for the TADS runtime executable is ".EXE"; for the game file it is ".GAM"; and for the output (executable) file it is ".EXE".
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Second, you can now omit everything except the name of the game file, and the program will attempt to provide defaults. If you omit the name of the TADS runtime executable, MAKETRX looks for a copy of TR.EXE in the same directory as the MAKETRX program; so
, if you simply keep all of your TADS executables in a single directory, you don't need to specify the location of TR.EXE when running MAKETRX. If you omit the destination filename, MAKETRX will use the same name as the game file, with the extension replac
ed by ".EXE".
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>The new command line formats for MAKETRX are:
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Converts MYGAME.GAM into MYGAME.EXE, using the copy of TR.EXE that resides in the same directory as MAKETRX.EXE.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Converts MYGAME.GAM into MYPROG.EXE, using the copy of TR.EXE that resides in the same directory as MAKETRX.EXE.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Converts MYGAME.GAM into MYPROG.EXE, using C:\TADS2\TR.EXE as the runtime executable.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The MAKETRX command (the Executable Game Builder on the Macintosh) now takes an additional parameter that lets you specify the run-time command options that should be used when the game is executed. MAKETRX still accepts the original command formats; using
one of the old-style command formats will not bind any command options into the resulting .EXE file, in which case the game will use the default runtime settings.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>To specify command options for your game executable, you must first create a file containing the command options. Use the same format as CONFIG.TR--simply enter your options into the file as you would on the TR command line; separate options by newlines or
spaces. For example, to specify a minimal cache size and a swap file of SWAP.DAT, you could make your CONFIG.TR file look like this:
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>For DOS users: Once you've created a file with your command options, specify that file to MAKETRX by using it as the first parameter on the command line, prefixed with an "at" sign (@):
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The @config option can be used with any of the original command formats for MAKETRX. Once the options file is bound into your executable, its options will be used every time a player runs your game's .EXE file.
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>For Macintosh users: an extra dialog has been added at the end of the process of building the application. This new dialog asks you for the options file you want to bind into your game. If you don't want to include an options file, simply hit "Cancel."
Otherwise, select the file containing the options and hit "OK." Note that the options file for the Macintosh version is in the same format as for the DOS version; refer to the
<+">Author's Manual<-"> for information on the format of the run-time command options.
<:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Note that you may should avoid specifying anything specific to your system in your options file, such as drives or directories, since doing so may prevent the game from working properly on someone else's system. For example, if you specify the swap file as
"D:\SWAP.DAT," the game won't work on a system that doesn't have a "D:" disk, since TADS will be unable to create a swap file on a drive that doesn't exist.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>DOS: Ctrl-Left and Ctrl-Right Arrow Keys<-!>
<:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The DOS runtime now lets the player move the cursor to the start of the next word wit control-right arrow, and to the start of the previous word with control-left arrow. This is consistent with many other DOS command-editing environments.
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The DOS runtime now has a plain ASCII mode, in which it uses only DOS character input/output functions. When in plain ASCII mode, the DOS runtime won't use any low-level I/O functions, such as BIOS or memory-mapped video, but goes entirely through DOS. Th
e runtime also won't display the status line or any highlighting. If you have a special need for DOS-only I/O (for example, if you want to use a voice synthesizer to read the text generated by the game), you can use this mode.
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>To tell the runtime to use plain ASCII mode, specify <:f200,QCourier New,>-plain<:f> on the runtime command line:
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>You can also specify -plain to an executable game, as long as the game executable was built using a version of the runtime (such as 2.2) that supports the plain ASCII mode:
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The output formatter's handling of hyphenation has been improved. In particular, the output formatter will not split multiple consecutive hyphens across lines; if you use two or three hyphens together as a dash, the formatter will no longer split these up
across lines. In addition, the formatter will keep hyphens at the end of a line, and will not break a line in such a way that it starts with a hyphen.
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The Macintosh formatter has been fixed so that it no longer inserts spaces after hyphens when the spaces weren't in the original text.
<:s><:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Escapes in askfile Prompts<-!>
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Prompt strings passed to <:f200,QCourier New,>askfile<:f> can now contain
<:f200,QCourier New,>\n<:f> and <:f200,QCourier New,>\t<:f> sequences; these sequences are converted properly for display in the dialog.
<+C><:s><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The DOS file selector has been corrected so that the Alt-key mappings are correct. In a previous version, the Alt-key mappings were off by one (Alt-B selected the A drive, for example).
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The Macintosh runtime's initial file selector dialog, which lets you specify the game you want to run, now has an "All Files" button. Clicking this button makes the file selector show
<+">all<-"> files, rather than just files that have the special signature that indicates they were created by the Macintosh version of the TADS compiler. If you've transferred a .GAM file from a non-Macintosh system, you can use the "All Files" button to o
pen the file--you no longer have to use ResEdit or another file utility to set the creator and type flags in the file.
<:I0,0,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f,2MinioMM_345 wt 585 wd 12 op,><+!>Status Line on Startup<-!><:f>
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The runtime system (on both DOS and Macintosh) no longer displays anything as the game is being initialized. In previous versions, the runtime displayed "TADS" at the left end of the status line, and "0/0" at the right end, until the game changed the displ
ay. This was slightly incongruous for games that changed to a different status line format. The status line is now completely blank during game initialization.
<+C><:I0,432,0,0><:S+273><:R1,15,1,72,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Note that this change may have a slight effect on your game: by default, the score/turn area of the status line will be completely blank until a call to
<:f200,QCourier New,>setscore()<:f> is made. To compensate for this change, we've added a call to
<:f200,QCourier New,>scoreStatus(0, 0)<:f> at the beginning of the
<:f200,QCourier New,>init<:f> function defined in adv.t. If you provide your own
<:f200,QCourier New,>init<:f> function, you may want to initialize the status line's score display in your
<:f200,QCourier New,>init<:f>; if you don't, the status line's score/turn area will be empty until the player enters the first command, at which point the normal turn-counting daemon will usually update the status line.
<+C><:I0,432,0,0><:S+273><:R1,12,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The compiler now sets system exit codes according to whether any errors occurred during compilation. If there are no errors (even if there are warnings), the compiler sets the exit code to 0. If any errors occur, the compiler sets the exit code to a non-z
ero value. This makes the compiler work better with "make" utilities, since these utilities usually check the exit code of each command to determine if the operation encountered an error.
<+C><:s><:I0,432,0,0><:S+273><:R1,12,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>In addition, the compiler will no longer generate a .GAM file if any errors occur. In the past, the compiler generated a .GAM file in most cases, even when the source file contained errors. Attempting to run a .GAM file produced from a source file with er
rors had unpredictable results.
<+C><:s><:I0,432,0,0><:S+273><:R1,12,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The Macintosh compiler now displays a different message if a compilation fails or is interrupted than it does when the compilation completes successfully. The compiler displays "Compilation Terminated" if errors occur; it still displays "Compilation Comple
@Title@<:s><:S+417><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#417,6624><:f720,BMezzMM_585 BD,>The New Book of the Parser<:f>
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><+"> Chapter Four of the <-">TADS Author's Manual<+"></`>describes the player command parser as it was in version 2.0. Since then, we've added substantial new functionality to the parser. For the past few releases, we described the new features as they we
re added, but until now there was no single source of information on the parser<-"><+">; as a result, it was often difficult to see how the new features and the original features worked together.
<-"><+"> This section covers <-">all<+"> of the parser's features--new and old--and is intended to replace Chapter Four of the
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If you were going to write a text adventure game, and you didn't have a system such as TADS, you would be faced with the daunting prospect of designing a player command parser. The job is so large that you'd probably spend more time designing and implementi
ng your parser than on any other part of the game.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Fortunately, if you're taking the time to read this, you're at least thinking about building your game with
<:f,2MinioMMSC_367 RG 585 NO 11 OP,>TADS<:f>, which means that you won't have to write your own parser. Using an existing parser will save you a vast amount of work, but won't eliminate your work entirely: you won't have to write your own parser, but you w
ill have to learn enough about the parser you're using to write your game.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3822,6624>With TADS, the amount you need to learn depends on what you want to do. You can do quite a lot with TADS without learning anything at all about the parser--by using existing class libraries (such as the standard library adv.t supplied with TADS), you can cr
eate objects whose interactions with the parser have already been defined, so that all you need to do is fill in some simple information on the objects, such as their names and descriptions. Once you've become comfortable with the basics of writing TADS gam
es, though, you'll want to create your own object classes, with their own interactions with existing verbs; to do this, you'll have to learn a little bit about how the parser processes commands, so that you can add code to your new objects that lets them re
spond to certain commands. You'll probably also want to be able to create your own verbs, which requires that you learn how to define your own commands. After you've done all of this, you may want to start making more complicated changes, which will require
that you learn about some of the more esoteric aspects of the parser.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,>The first part of this chapter is an overview of what you need to know about parsing to get started with TADS: how to create objects and give them names the player can use in commands; how to make customize the way your objects respond to commands; and how
to create your own new commands. One of the nice features of TADS is that you can write games almost immediately, and fill in your knowledge with more detail as you go. This section is intended to help you get started--we begin with the minimum information
you need, and then move on to the more advanced features.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The very least you have to learn about the parser to write a game is: nothing! That's because you can write a game using only objects that have been defined already--for example, you can use the objects defined in adv.t, the library of common adventure ob
jects included with TADS. To create a box, which can be opened and closed (but starts off open), you would only have to write this code:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The class <:f200,QCourier New,>openable<:f> (defined in adv.t) has already been set up to respond to the commands appropriate for a container that can be opened and closed--it automatically knows how to respond to all of these commands from a player:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>open the box
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>look in the box
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>put everything in the box
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>the the ball out of the box
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>put the book in the box, and close the box
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Although we said you didn't have to know anything about parsing to use objects defined in adv.t, you actually have to know a little bit about parsing: you have to know how to give an object a name.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>In the object above, we defined a property called <:f200,QCourier New,>noun<:f>, which we set to
<:f200,QCourier New,>'<:f><:f200,QCourier New,>box'<:f>. The <:f200,QCourier New,>noun<:f> property is special--it's a
<+">vocabulary<-"> property. Vocabulary properties assign names to an object that the player can use in commands; the vocabulary properties are
<:f200,QCourier New,>article<:f>, and <:f200,QCourier New,>verb<:f>. For the most part, you will define
<:f200,QCourier New,>noun<:f> and <:f200,QCourier New,>adjective<:f> vocabulary properties; you won't need to use the others until you start defining new commands of your own. Note a very important feature about vocabulary properties: the value of a vocabu
lary property must always be a single-quoted string.
<:s><:I0,360,1530,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f,BGillSans,> Theorem 1. <:f><+">A vocabulary string must be in single quotes.<-">
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Vocabulary properties are different from normal properties. Their only function is to define words that the player can use to refer to the object. Unlike ordinary properties, vocabulary properties can't be used from within your game program. For example,
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The property <:f200,QCourier New,>box.noun<:f> simply has no value at run-time. You can't use the vocabulary properties to get the vocabulary words for an object at run-time; however, you
<+">can<-"> get these properties using the built-in function <:f200,QCourier New,>getwords()<:f>.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>When you assign a vocabulary property to an object, you create a word that the player can use in a command, and you assign the word a particular "part of speech." A word's part of speech determines how the word can be used in a sentence, the same way it do
es in ordinary speech. When you define a word in a <:f200,QCourier New,>noun<:f> property, you're specifying that the word can be used in a player's commands wherever a noun is grammatically valid. You're also specifying that the word refers to this particu
lar object.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The same word can be assigned to multiple objects. For example, you may have several objects in your game that all have the noun "box." In addition, the same word can be used as multiple parts of speech. For example, you might have one object in your game
called a "paper towel," and another called a "term paper"; the word "paper" in this case can be used as either a noun and an adjective.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>You can also define more than one of the same part of speech for an object. In many cases, you will want to provide several synonyms for an object's words. You can do this easily--simply list all of the synonyms in the vocabulary property for each part of s
peech. For example, if you have a booklet in your game, you may want to provide a number of similar words that the player can use to refer to the object:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> ldesc = "It'<:f><:f200,QCourier New,>s a small booklet labeled<:f>
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Notice that each word in each list is enclosed in single quotes. With this definition, you could refer to the booklet as "release notes," or "small tads booklet," or any other combination of these adjectives and nouns.
@Header@<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Responding to Commands
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Adv.t defines many types of objects that are common in adventure games, and you will probably be able to write a substantial part of your game using only these objects. However, a game that only involved objects from adv.t would be very dull, so you'll soon
want to be able to create objects of your own that respond in novel ways to certain commands. To do this, you'll need to understand how verbs are applied to objects.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#4368,6624>Each command that the parser understands has a set of methods that it calls in the objects making up the command (a method is simply a function or subroutine that's associated with a particular object). When the player types a command that involves a verb a
nd a noun, the parser figures out which methods to call based on the verb, and then calls these methods in the object specified by the noun. For example, the verb "open" has two methods that it calls in the object being opened: it has a
<+">verification<-"> method named <:f200,QCourier New,>verDoOpen<:f>, and an
<+">action<-"></`>method called <:f200,QCourier New,>doOpen<:f>. (The "do" in these names stands for "direct object"--it's not meant to be the verb "do.") The verification method is used to determine if the object is logical with the verb--for "open," an o
bject is logical if it can be opened and closed in the first place, and if it's not already open. The verification method doesn't have to test to see whether the object is accessible to the player, because this testing is done separately; this method only h
as to check to determine if the object makes sense with the verb. The action method carries out the verb; it doesn't have to check to see whether the object makes sense with the command, since the verification method has already done this.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Suppose you wanted to make an object that does something unusual when opened. For example, you might want to have a can that contains a spring-loaded snake that jumps out when the can is opened. To do this, you'd customize the can's handling of the "open" c
ommand.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>If we make the can an <:f200,QCourier New,>openable<:f>, as we did with the box, we'd get the automatic handling of opening and closing the can. However, we want some additional behavior--when the object is opened, and it contains the snake, we want the sna
ke to jump out. To do this, we'll <+">override<-"> the <:f200,QCourier New,>verDoOpen<:f> method that's defined by the
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (snake.isIn(self))
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> " As you open the can, a spring-loaded
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> fake<:f><:f200,QCourier New,> snake leaps out! You'<:f><:f200,QCourier New,>re so
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> surprised that you <:f><:f200,QCourier New,>drop the can.";
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The first thing the new action routine does is to <+">inherit<-"> the default
<:f200,QCourier New,>doOpen<:f> that was defined by <:f200,QCourier New,>openable<:f> in adv.t. When overriding a method, it's often useful to be able to incorporate the original method from the class--the
<:f200,QCourier New,>inherited<:f> keyword lets you do this. The inherited default
<:f200,QCourier New,>doOpen<:f> opens the can as usual. After that's been done, we check to see if the snake is in the can; if so, we take our special action: display a message telling the player about the snake, then moving both the can and the snake to t
he player's location.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3276,6624>There are a couple more things to notice in this example. One is the parameter
<:f200,QCourier New,>actor<:f>. Whenever a verification or action routine is called, the system includes the actor to whom the command was directed as an argument. When the player types a command without specifying an actor, the player's actor
<:f200,QCourier New,>Me<:f> is used by default--<:f200,QCourier New,>Me<:f> is a special object that refers to the player. You can always find out what room the player is in with
<:f200,QCourier New,>Me.location<:f>, and you can find out what the player is carrying with
<:f200,QCourier New,>Me.contents<:f>. However, by writing our <:f200,QCourier New,>doOpen<:f> method in terms of the actor object passed as a parameter, we can make it possible for the player to direct commands to other characters in the game, and have the
commands work properly. So, rather than moving the snake and the can to
<:f200,QCourier New,>Me.location<:f>, we moved them to <:f200,QCourier New,>actor.location<:f> (which will be the same thing if the player was opening the can him or herself).
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>If you wanted to make the command even more adaptable to another character, you should replace some of the text in the message with special "format strings":
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>" As %you% open the can, a spring-loaded
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>fake<:f><:f200,QCourier New,> snake leaps out! %You'<:f><:f200,QCourier New,>re% so
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>surprised that %you% <:f><:f200,QCourier New,>drop%s% the can.";<:f>
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>The special sequences in percent signs, such as "<:f200,QCourier New,>%you%<:f>", are converted by the system automatically to an appropriate word based on the current actor. If the command is being carried out by the player actor, the message displayed is
the same as the original; however, if the command is directed to another character in the game, the terms are all replaced by something appropriate to that character. In most games, the non-player characters can only carry out certain selected commands, so
you only need to worry about this when you're writing a command that can be directed to a character. All of the command handlers in adv.t are written this way, but you only need to worry about the ones you know can be carried out by a non-player character.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Note that we only had to change the action (<:f200,QCourier New,>doOpen<:f>) routine--we didn't do anything to the verification (<:f200,QCourier New,>verDoOpen<:f>) routine, because the one we inherited from
<:f200,QCourier New,>container<:f> already does what we need.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Now suppose we wanted to handle another verb; but this time, it's one that the object doesn't inherit from its class. Let's suppose that we want to make it possible to read the can's label, but only after the can has been cleaned. For this, we'll need to ne
w verbs, "read" and "clean," both of which are defined in adv.t. As with "open," these verbs each have a verification and an action method. We'll add the following code to the can:
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (self.isClean)
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "You can'<:f><:f200,QCourier New,>t make it much cleaner.";
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "You wipe off the label. It'<:f><:f200,QCourier New,>s much more
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (not self.isClean)
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "It's far too dirty.";
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "It's labeled<:f><:f200,QCourier New,> \"Snake in a Can.\"";
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The verification routine is a little strange, because it doesn't seem to do anything--all it does is check to see whether the command makes sense, and displays a message if not. This is, in fact, all that a verification routine should
<+">ever<-"></`>do. The most important thing to remember about verification routines is that they must
<+">never<-"> modify the game's state in any way--for example, they must never set a property's value. Only the action routine should change game state.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f,BGillSans,>Theorem 2<:f><:f,BGillSans,>. <:f><+">Never modify any game state in a verification routine.<-">
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#4641,6624>The reason that verification methods shouldn't change any game state is that these methods are sometimes called "silently" by the parser; that is, the parser turns off the output, and calls a verification method. The player will never know that the method h
as been called at all, because any text it displayed was suppressed--this is what we mean when we say that the method is called "silently." The parser makes these invisible calls to verification methods when it's trying to figure out which of several possi
ble objects the player means. For example, suppose the player is in a room with two doors, one red and one blue, and the red door is open and the blue door is closed; if the player types "open door," the parser calls the verification routine on each door to
determine which one makes the most sense. The red door's verification method will display a message saying that you can't open it because it's already open; the blue door's method will say nothing. These calls are made with the text output turned off, beca
use the parser isn't really trying to open anything at this point--it's merely trying to figure out which door makes more sense with the command. Once it's decided which one to open, the parser will run the verification method with output turned on, and the
n it will run the action method.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>How does a verification method tell the parser that the command is not logical? Simple: it displays a message. So, the verification routine's only function is to display an error. If the verb is logical for the object, the verification method doesn't do a
nything at all--since the verb makes sense, there's no error to display. If the verb does
<+">not<-"></`>make sense, the verification method displays an error message telling the player why the verb can't be used. The parser sees the message, and knows that it indicates that the verb can't be used, so it won't try to run the action routine.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>There's another important feature of the verification method: if an object doesn't have a verification method defined at all--which means that the object neither defines the verification method itself nor inherits the method from a superclass--the command
automatically fails, and the parser generates the message "I don't know how to
<+">verb<-"> the <+">object<-">." So, if you want an object to be able to carry out a command, you
<+">must<-"></`>either define the verification method directly in the object, or make sure the object inherits the verification method from a class.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Once you start writing your game, you'll quickly want to start adding your own new commands. One of the features that makes TADS so powerful is that it has
<+">no<-"></`>built-in verbs--all of the verbs you've seen so far are defined in adv.t, not within TADS itself, so you can change, replace, or remove any of them, and, of course, add new verbs of your own.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>We've already mentioned that there's a vocabulary property called
<:f200,QCourier New,>verb<:f>; as you might guess, this is the vocabulary property that you use to add a new command. You may wonder what sort of object you attach the
<:f200,QCourier New,>verb<:f> property to. The answer is that there's a special kind of object defined in adv.t, called
<:f200,QCourier New,>deepverb<:f>, that you can use as a command object. This isn't an object that the player sees as part of your game--it's merely an abstract, internal object, whose purpose is to contain the data and methods that define a new command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>TADS allows you to create three basic types of commands: a command that consists simply of a verb, such as "look" or "jump"; a command that has a verb and a direct object, such as "take book" or "turn on the flashlight"; and a command that has a verb, a di
rect object, a preposition, and an indirect object, such as "put the ball in the box" or "clean the lens with the tissue." The same word can be used in more than one form of command; for example, you might define commands such as "lock door" and "lock door
with key."
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>For the first type of sentence, which has only a verb, you define the entire command in the
<:f200,QCourier New,>deepverb<:f> object. You specify the action that the verb carries out with a method called
<:f200,QCourier New,>action<:f> that you define in the <:f200,QCourier New,>deepverb<:f> object. For example, to define a verb called "scream" that displays a message, you could do this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The presence of the <:f200,QCourier New,>action<:f> method in the object that defines the verb allows the command to be used without any objects. If you define a
<:f200,QCourier New,>deepverb<:f> that doesn't have an <:f200,QCourier New,>action<:f> method, and the player types the verb without any objects, the parser asks the player to supply a direct object, because the parser can't execute the command without any
objects when no <:f200,QCourier New,>action<:f> method is present.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>For the second type of sentence, which has a verb and a direct object, you must set up a
<:f200,QCourier New,>deepverb<:f> object--but, as you have already seen, the command is carried out by the direct object, not by the verb itself. The
<:f200,QCourier New,>deepverb<:f> object serves to tell the parser about the verb and how it works--it contains the
<:f200,QCourier New,>verb<:f> property, and also has the <:f200,QCourier New,>doAction<:f> property. The
<:f200,QCourier New,>doAction<:f> property is a special property that tells the system that the command can be used with a direct object (the "<:f200,QCourier New,>do<:f>" in
<:f200,QCourier New,>doAction<:f> stands for "direct object," just as it did with methods such as
<:f200,QCourier New,>doOpen<:f>), and tells the system what the verification and action methods are called.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Here's how it works: you define the property <:f200,QCourier New,>doAction<:f> in the
<:f200,QCourier New,>deepverb<:f> as a single-quoted string. The parser takes the string '<:f200,QCourier New,>verDo<:f>' and puts it in front of your string--this becomes the name of the verification property. The parser then takes '<:f200,QCourier New,>do
<:f>' and puts it in front of your string--this becomes the name of the action property. For example, if you define a verb to scream at someone, and you specify
<:f200,QCourier New,>doAction = 'Screamat'<:f>, then the verification method for your new command is
<:f200,QCourier New,>verDoScreamat<:f>, and the action method is <:f200,QCourier New,>doScreamat<:f>. Here's how your
<:f200,QCourier New,>deepverb<:f> definition would look:
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>If the player types "scream at the phone," the parser first calls the
<:f200,QCourier New,>verDoScreamat<:f> method in the phone object, to verify that the command is sensible; if the verification method is defined, and succeeds (which means that it doesn't display any messages), the parser proceeds to call the
<:f200,QCourier New,>doScreamat<:f> method, which should carry out the action of the command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>There are two more things to notice in this example.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3549,6624>The first is that the <:f200,QCourier New,>verb<:f> property we defined has two words. This is a special ability of the
<:f200,QCourier New,>verb<:f> property--you can't do anything similar for
<:f200,QCourier New,>noun<:f>, <:f200,QCourier New,>adjective<:f>, or any of the other vocabulary properties. If you define a two-word verb, you must separate the two words by a space, and you must define the second word as a preposition. (In this case, "at
" is already defined as a preposition in adv.t, as are most English prepositions. If you add a two-word verb, be sure that the second word is defined as a preposition; if it's not so defined in adv.t, you must define it in your game's source code.) Two-wor
d verbs are useful, because many English verbs take this form. When a verb has a direct object, TADS lets the player use the second word immediately after the verb, or at the end of the sentence. With "scream at," the latter doesn't make much sense, but for
many verbs it does--for example, you might say "pick up the book," but it would be equally valid to say "pick the book up." TADS understands both.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>The second thing to notice is the use of capitalization in the <:f200,QCourier New,>doAction<:f> string. The convention used by adv.t is to capitalize the first letter of a preposition, but
<+">only for verbs that take an indirect object. <-">For example, adv.t defines an
<:f200,QCourier New,>ioAction<:f> of <:f200,QCourier New,>GiveTo<:f> for the command "give
<+">object<-"></`>to <+">actor<-">"; the To is capitalized because "to" is the preposition that introduces an indirect object. For our verb here, we don't have an indirect object--the preposition is part of the verb, rather than a word that introduces an in
direct object--so we do <+">not<-"> capitalize the "at" in <:f200,QCourier New,>Screamat<:f>. You don't have to use this convention, since the string that you define in a
<:f200,QCourier New,>doAction<:f> is entirely up to you, but it may help you to make sense of adv.t if you know the convention it uses.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The third type of sentence has both a direct object and an indirect object, and has a preposition that introduces the indirect object. For example, you might want to create a command such as "burn paper with torch." To define this command, you use the
<:f200,QCourier New,>ioAction<:f> property of the deepverb. This property is similar to
<:f200,QCourier New,>doAction<:f>, but it defines <+">three<-"></`>new methods, and also associates a preposition with the command:
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Notice that <:f200,QCourier New,>'BurnWith'<:f> follows the capitalization convention described earlier. Since the preposition introduces an indirect object, and isn't merely a part of the verb, we capitalized its first letter.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The association of the preposition is done with the <:f200,QCourier New,>withPrep<:f> in the parentheses--<:f200,QCourier New,>withPrep<:f> is an object, defined in adv.t, which specifies a
<:f200,QCourier New,>preposition<:f> property that defines the vocabulary word "with." The
<:f200,QCourier New,>withPrep<:f> object is of class <:f200,QCourier New,>Prep<:f>, which is similar to
<:f200,QCourier New,>deepverb<:f>: it's an abstract type of object that isn't visible to a player, and its only function is to define the vocabulary word and associate it with an object that can be referenced from within your game program.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>This definition tells the parser that sentences that start with the verb "burn" must have a direct object, and an indirect object, and that the objects are separated with the preposition "with." When a sentence matching this pattern is entered by the playe
r, the parser will use this verb definition to execute the command.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3276,6624>We mentioned that an <:f200,QCourier New,>ioAction<:f> defines three methods. Recall that
<:f200,QCourier New,>doAction<:f> defines two methods from its root string: a verification method (starting with
<:f200,QCourier New,>verDo<:f>), and an action method (starting with
<:f200,QCourier New,>do<:f>). The <:f200,QCourier New,>ioAction<:f> property similarly defines verification and action methods, but since two objects are involved, it must generate not one but two verification methods: one for the direct object, and anothe
r for the indirect object. The methods are called <:f200,QCourier New,>verIoBurnWith<:f> and
<:f200,QCourier New,>verDoBurnWith<:f>. As you might guess from the names,
<:f200,QCourier New,>verIoBurnWith<:f> is sent to the indirect object, and
<:f200,QCourier New,>verDoBurnWith<:f> goes to the direct object--and they're called in that order, with the indirect object going first. If
<+">both<-"></`>verification methods are defined and successful, then the parser calls the action method,
<:f200,QCourier New,>ioBurnWith<:f>--this is called only for the indirect object. The parser never calls an action method in the direct object for a two-object command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The verification and action methods for verbs with two objects are a little different than those for single-object verbs. Whereas a single object verb's verification and action methods only take the actor as a parameter, two of the two-verb methods get an a
dditional parameter: the other object. The remaining method only gets the actor. The definitions should look like this:
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>This may seem strange, but there's a reason. Since the parser calls
<:f200,QCourier New,>verIoBurnWith<:f> first, it doesn't always know what the direct object is when it calls
<:f200,QCourier New,>verIoBurnWith<:f>. As a result, it can't provide it as a parameter. By the time it calls
<:f200,QCourier New,>verDoBurnWith<:f>, though, the indirect object is known, so the extra parameter is provided.
<:f200,QCourier New,>ioBurnWith<:f> is called later still, so the extra object is also provided as a parameter there.
<:I0,360,1440,0><:R1,13,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f,BGillSans,>Theorem 3.<:f> <+">verIoXxxx does <+!>not<-!></`>have a dobj parameter.<-">
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>You may notice that there are some methods defined in adv.t that might make you think that the parser also calls
<:f200,QCourier New,>doBurnWith<:f>. In fact, the parser will never call
<:f200,QCourier New,>doBurnWith<:f> itself, but this is a perfectly valid method name which you can call from your own code. Sometimes, you will want the action of a two-object verb to be carried out by the indirect object, and other times you'll want to us
e the direct object. Which way is better depends entirely on the situation--in general, the better way is the one that requires you to write less code. If you find a situation where you want to handle a two-object command's action in the direct object rathe
r than in the indirect object, simply write an indirect object action routine that looks like this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The parser will never call <:f200,QCourier New,>doBurnWith<:f>, but there's nothing to stop you from calling it.
<:I0,360,1440,0><:R1,13,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f,BGillSans,>Theorem 4.<:f> <+">The parser never calls d<-"><+">oXxxx for a two-object verb.<-">
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>If you find yourself in a situation where the standard order of verification for a two-object verb is wrong, TADS does let you change this default ordering. We're moving into advanced territory here, so you probably won't need to know this for quite a while
, but you might at least want to note that it's possible. When you define an
<:f200,QCourier New,>ioAction<:f>, you can include a special modifier that tells TADS to change the ordering:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The modifier is the strange-looking word in square brackets; it tells TADS that you want to reverse the normal ordering. When you include this modifier, the parser will process the verification and action methods in a different order than usual:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Note that the parameters changed along with the order. Since the direct object is processed first for this command, the direct object verification routine is called before the indirect object is known, and hence no indirect object is passed to it; and since
the indirect object verification routine is called after the direct object is already known, the direct object is supplied as a parameter to this routine.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Adding to an Existing Verb
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>As you add your own new commands, you will probably find that you want to augment the definition of one of the verbs defined in adv.t. For example, you may want to add a new command such as "open crate with crowbar." Since a verb for "open" is already defi
ned in adv.t, you can't create another "open" verb in your own game. Fortunately, TADS lets you supplement an existing verb without having to change the original definition's source code.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>To change an existing verb, you can use the TADS <:f200,QCourier New,>modify<:f> statement. This statement lets you add properties to an object that has already been defined elsewhere in your game (even in a separate file that you include, such as adv.t).
For example, to modify the "open" verb defined in adv.t to add an "open with" command, you would do this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>We strongly recommend that you use the <:f200,QCourier New,>modify<:f> mechanism whenever possible, rather than making source changes to adv.t. If you edit adv.t directly, you may find that you have a lot of work to do when you upgrade to a new version of T
ADS, because we will probably modify adv.t--if you also modify it, you will have to figure out how to apply your changes to the new version of adv.t If you use the
<:f200,QCourier New,>modify<:f> mechanism instead, you should be able to use future versions of adv.t without any additional work.
@Header@<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Overview of Disambiguation
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>As you build your game, you will probably add multiple objects that all go by the same name. When you give the same noun to two or more objects, you create the possibility that a player can type in a command with an ambiguous object name--that is, the words
that the player uses refer to more than one object. For example, if you create several books in your game, you will probably give them all the noun "book"; a command such as "take book" could refer to any of these objects. Fortunately, the TADS parser has
a powerful system that can resolve ambiguous object names; in many cases, the parser can disambiguate objects automatically, without needing any help from the player.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The first step in disambiguating an object name is to apply the visibility and access rules. These rules, which are defined by objects in your game program, determine whether an object is visible to the player, and if so whether it can be used with a partic
ular verb. If an object is neither visible, nor accessible for use by the player with the given verb, the object isn't considered further. If it's visible but not accessible, it will be considered only to the extent that there isn't another object which
<+">is<-"> accessible.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Visibility is determined by the method <:f200,QCourier New,>isVisible<:f>, which is defined for each game object. The general-purpose class
<:f200,QCourier New,>thing<:f> defined in adv.t provides a definition of this method suitable for most objects; you will probably not need to make any changes to this method unless you need some special effect. To determine if an object is visible to the pl
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Accessibility is determined by the <:f200,QCourier New,>deepverb<:f> object. For a direct object, the parser first calls the method
<:f200,QCourier New,>validDoList<:f>, which returns a list of all objects which are
<+">possibly<-"> valid for the verb; the objects in the list aren't necessarily valid, but any objects
<+">not<-"></`>in the list are <+">not<-"></`>valid. If <:f200,QCourier New,>validDoList<:f> returns
<:f200,QCourier New,>nil<:f>, it means that <+">all<-"> objects are possibly valid and should be considered. A similar method,
<:f200,QCourier New,>validIoList<:f>, returns a list of possibly-valid indirect objects.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>After eliminating any objects that aren't in the <:f200,QCourier New,>validDoList<:f> (or
<:f200,QCourier New,>validIoList<:f>, as appropriate), the parser submits each surviving object to the method
<:f200,QCourier New,>validDo<:f>, also defined in the <:f200,QCourier New,>deepverb<:f> object. This method takes the object as a parameter, and returns
<:f200,QCourier New,>true<:f> if the object is valid for the verb,
<:f200,QCourier New,>nil<:f> if not. The parser keeps only objects that are valid.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>If any objects remain, the parser turns off output and calls the appropriate validation method in each object. This is the "silent" validation call that we mentioned earlier. If only one of the objects passes the validation test (that is, the validation met
hod doesn't attempt to display any messages), that object is chosen. Otherwise, the parser gives up and asks the player which of the objects to use.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The silent validation test lets TADS be very intelligent about disambiguation. For example, if there's an open door and a closed door in the room, and the player types "open door," the validation test lets the system determine that the player means to open
the closed door--since the <:f200,QCourier New,>verDoOpen<:f> method fails for the open door (it displays "It's already open" if the default verification method from adv.t is used), but succeeds for the closed door, the parser knows to choose the closed doo
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The second half of this chapter, "The Parser in Detail," has full details on how disambiguation works.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624><:ZDefaultObjects><:Z~DefaultObjects>Default objects and "All"
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The parser also tries to be intelligent about supplying defaults when the player provides only partial information. The parser supplies default direct and indirect objects for commands that omit one of these objects, using rules defined by the objects in yo
ur game program.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>To determine a verb's default direct object, the parser calls the method
<:f200,QCourier New,>doDefault<:f> in the <:f200,QCourier New,>deepverb<:f> object. This method returns a list of default direct objects. The verbs in adv.t generally return a list of all accessible objects; a couple of verbs return more restricted lists (f
or example, "take" returns a list of accessible objects that aren't already in the player's inventory). Similarly, the parser calls the
<:f200,QCourier New,>deepverb<:f> method <:f200,QCourier New,>ioDefault<:f> to get a list of default indirect objects. When
<:f200,QCourier New,>doDefault<:f> (or <:f200,QCourier New,>ioDefault<:f>, as appropriate) returns a list that consists of exactly one object, the parser uses this object as the default for the command. If the list is empty, or consists of more than one obj
ect, the parser will ask the player to supply the object, because the command doesn't imply a particular object.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The parser's automatic default system can be especially convenient for indirect objects. Certain commands imply the use of particular indirect objects; for example, "dig" implies a shovel or similar tool. For such commands, it's a good idea to define
<:f200,QCourier New,>ioDefault<:f> methods that return a list of accessible objects that satisfy particular criteria; for "dig," you would return a list of accessible objects that are usable for digging.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>The <:f200,QCourier New,>doDefault<:f> method has another use: the parser calls these methods to determine the meaning of "all." When the player uses "all" as a direct object, the parser replaces "all" by the list returned by
<:f200,QCourier New,>doDefault<:f>. Since the parser doesn't allow using a command to include multiple indirect objects, "all" cannot be used as the indirect object, hence
<:f200,QCourier New,>ioDefault<:f> will never be used to supply a list for "all." Note that you can disallow using "all" (and multiple direct objects in general) for a particular verb by defining the property
<:f200,QCourier New,>rejectMultiDobj<:f> to be <:f200,QCourier New,>true<:f> in the
<:f200,QCourier New,>deepverb<:f>. Here's an example of using <:f200,QCourier New,>rejectMultiDobj<:f> to prevent the player from being able to look at everything in the room all at once:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "You can only look at one thing at a time.";
@Subhead@<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#572,6624>The Parser in Detail
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The rest of this chapter is devoted to the details of how the parser works. The sections are organized in roughly the same order as the steps the parser executes as it analyzes and executes a player's command.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>When the player types a line of text into your game, the TADS parser goes through a series of operations to convert the command line into simple actions on objects in the game. In the course of these operations, the parser makes calls to your game program f
or advice; in most cases, the parser has default actions for these calls, so you don't need to include any code in your game program for the default behavior. You can, however, customize the parser by providing definitions for these "hooks" in your game. Th
e main purpose of this chapter is to describe the way the parser interacts with your game program, so that you can customize the parser by overriding the defaults. We also describe many of the internal operations of the parser so that you can understand how
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624><:ZReadingACommand><:Z~ReadingACommand>Reading a Command Line
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The first step in parsing is getting a command line from the player. The parser does this automatically, without any action by your game program, at the beginning of each turn. The parser displays its prompt, then waits for the user to enter a line of text.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>The prompt is the first parser default action that you can override: if your game defines a function called
<:f200,QCourier New,>commandPrompt<:f>, the parser will call this function when it needs to display a prompt; otherwise, it will display its default prompt, which is a greater-than sign (<:f200,QCourier New,><;><:f>). The
<:f200,QCourier New,>commandPrompt<:f> function is called with an argument that lets you display distinct prompts for different situations, if you wish; the default prompt is always the same, regardless of the type of input being requested, but you can use
different prompts for the different types of input if you prefer. The
<:s><:I0,720,1062,0><:S+-1><:R1,14,1,720,1,1062,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#240,6624>0 Used for normal commands.
<:s><:I0,720,1062,0><:S+-1><:R1,14,1,720,1,1062,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1440,6624>1 The player typed an unknown word, and the parser is reading a new command that can be an "oops" command. If the player types a command line that begins with the word "oops" (or "o"), the parser will substitute the next word for the unknown word in the pre
vious command, and go back to parsing the previous command. Otherwise, the parser treats the new line as a brand new command.
<:s><:I0,720,1062,0><:S+-1><:R1,14,1,720,1,1062,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1920,6624>2 The player has referred to an ambiguous object, and the parser wants the user to provide more information. The parser displays a message such as "Which book do you mean, the red book, the blue book, or the green book?", and then reads a command with promp
t 2. If the player types something that looks like an answer to the question (for example, "the blue one" or "green book" or simply "red"), the parser uses that information to disambiguate the object; otherwise, it treats the new line as a brand new command
<:s><:I0,720,1062,0><:S+-1><:R1,14,1,720,1,1062,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1440,6624>3 The player has typed a command that has no direct object, but the verb requires a direct object. The parser displays a message such as "What do you want to open?", then prompts with prompt 3. If the player responds with an object name, it is used as the d
irect object of the original command, otherwise the text is treated as a new command.
<:s><:I0,720,1062,0><:S+-1><:R1,14,1,720,1,1062,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#240,6624>4 The same as 3, but used to prompt for indirect objects.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>After the player has typed a command, the parser will tell your game about it by calling your
<:f200,QCourier,>preparse<:f> function. Immediately after reading the command line, the parser calls this function with the original text of the player's command as the argument. If you don't provide a
<:f200,QCourier,>preparse<:f> function in your game program, the parser skips this step. If you do provide a
<:f200,QCourier,>preparse<:f> function, it can return one of three values: it can return
<:f200,QCourier New,>true<:f>, in which case the command is processed as normal; it can return
<:f200,QCourier New,>nil<:f>, in which case the command is skipped entirely, and the parser immediately asks the player for a new command; or it can return a string, in which case the returned string is used as the command instead of the line of text typed
by the player.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Here's an example definition of <:f200,QCourier New,>commandPrompt<:f> that displays a long prompt for the first few commands, then changes to a shorter prompt. The longer prompt is not displayed when the parser asks the player a question.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (typ = 0 or typ = 1)
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (global.promptTurns << 5)
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "What do you want to do now?\n";
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> else if (global.promptTurns = 5)
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "Aren't you tired of this long prompt?
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> I sure am. From now on, the prompt
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> will just be like this:\n";
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>If the player enters a blank line in response to a command prompt, the parser calls a function called
<:f200,QCourier New,>pardon<:f> in your game program. You must provide a function with this name. This function takes no arguments; its only purpose is to provide an opportunity for you to display an error message when the player enters an empty command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,>pardon: function
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "I beg your pardon?";
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Breaking the command into words
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Once the parser has read a line of text from the user, the next step is to break the command into individual words. The parser does this based entirely on the characters in the command line--at this stage, it doesn't pay any attention to whether it recogniz
es any of the words. People who write compilers call this step "lexical analysis" or "tokenization," because it involves breaking up a string of characters into individual units (or "tokens") by classifying the characters and grouping related characters.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>First, the parser converts the entire command to lower-case. Next, the parser simply goes through the command line, and takes each group of letters and numbers to be a word, and keeps any strings enclosed in double quotes together.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>For example, assume the player types this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Joe, Go West, then type "hello, world!" on the Acme-Tech computer's keyboard.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>The parser converts this to a string of words and symbols:
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that the punctuation marks are all treated as separate words, and the spaces are all ignored. Note also that apostrophes and dashes are considered to be equivalent to letters, so things like "Acme-Tech" and "computer's" are treated as single words.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Checking for Special Words
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>After breaking the command into words, the parser checks the word list for the special words listed in your
<:f200,QCourier New,>specialWords<:f> directive. If your game doesn't provide a
<:f200,QCourier New,>specialWords<:f> directive, the parser has a built-in list that it uses (since adv.t provides a
<:f200,QCourier New,>specialWords<:f> directive, your game probably has one whether you've entered one or not). Any word in the word list that matches one of the special words is converted to a flag indicating that it is that special word.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that this conversion doesn't apply to the special word in the "of" slot. This special word is matched later, and not converted along with the other special words, because it is often useful for "of" to be an ordinary preposition, which wouldn't be poss
ible if it were converted at this point.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>As with the previous step, where the command was broken up into words, this step is done automatically by the parser without any calls to your game.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Assembling the Words into Commands
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The next step is to find the individual commands on the command line. The command line can be made up of multiple commands, separated by the words "then" or "and," or by various punctuation marks: commas, periods, exclamation points, and question marks.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The word "then," and the period, exclamation point, and question mark are unambiguous--they always separate commands. So, the first thing the parser does is scan through the command line, looking for one of these symbols. If it finds one or more at the begi
nning of the command, it simply discards them. Otherwise, it takes all of the words up to the first occurrence of one of these symbols, and treats that as a command. For example, consider this command:
<:s><:I0,360,720,360><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#384,6624><:f180,QCourier New,>Joe, go west, then open the door and the window and go east.<:f>
<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The parser takes the part up to the "then" as the first command. It keeps doing the same thing through the rest of the command, which means that it will at this point break the line up into two commands:
<:s><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#192,6624><:f180,QCourier New,>Joe, go west
<:s><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#192,6624><:f180,QCourier New,>open the door and the window and go east<:f>
<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Note that the word "and" and the comma are ambiguous, since they may separate entire commands, or objects within a single command. The parser delays any decisions about these symbols until it has further analyzed the command; so, although the second line ab
ove actually consists of two separate commands, the parser at this point is considering it to be a single command.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The parser now processes these commands individually. It processes each part of the command in sequence, until either it has processed all of the commands, or an error occurs, or your game program executes an
<:f200,QCourier New,>exit<:f> or <:f200,QCourier New,>abort<:f> command.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624><:ZCheckActor><:Z~CheckActor>Checking for an Actor
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Now the parser starts processing the individual commands making up the command line. The first thing it does is to check for an actor prefix. The player can specify that a command is to be given to a particular actor by putting the actor's name followed by
a comma at the very start of a command. The sentence "Joe, go west" starts with an actor's name and a comma, so the command "go west" is directed to Joe.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Checking for an actor is the first processing of the command that involves the vocabulary words defined by your game (other than the special words). To determine if the group of words in front of the comma is indeed the name of an actor, the parser looks at
each word in turn, and applies the noun-checking rules; see the section on noun phrases (page
<:X3,-16384;PageRef NounPhrases>80<:X~3,-16384;PageRef NounPhrases>) for details on these rules.
<+C><:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>If the words do form a noun phrase, the parser will next attempt to determine if the noun phrase refers to an object that can be used as an actor. To do this, it first forms a list of all of the objects in the game that match all of the words in the noun ph
rase. For example, if the sentence starts with "black knight," the parser builds a list of all of the objects in the game that have both the adjective "black" and the noun "knight." If the list has more than one object, the noun phrase is ambiguous, so the
parser must "disambiguate" the object to determine what the player intended.
<+C><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>First, the parser goes through the list and notes which objects in it are visible. To do this, it calls the method
<:f200,QCourier New,>isVisible(Me)<:f> on each object in the list--this method returns
<:f200,QCourier New,>true<:f> if the object is visible from the given vantage point (<:f200,QCourier New,>Me<:f>, the player actor),
<:f200,QCourier New,>nil<:f> if not. This step is used entirely to determine how to report any errors that happen later; an object may be visible, but not valid as an actor, in which case a different message is required than if the object isn't present at a
<+C><:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>Next, the parser determines whether each object can be used as an actor. For each object, the parser calls the
<:f200,QCourier New,>validActor<:f> method, which returns <:f200,QCourier New,>true<:f> if the object can be used as an actor. The default definition of this method in adv.t returns
<:f200,QCourier New,>true<:f> for any object if the object can be reached by the player. You can override this method to achieve different effects; for example, if the player is carrying a walkie-talkie, you could make any actors that have the other walkie-
talkie valid as actors, since they can hear the player through the radio, even though they may not be in the same room.
<+C><:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Note that <:f200,QCourier New,>validActor<:f> is intended to determine whether an object is
<+">valid<-"> as an actor, not necessarily whether the object is <+">logical<-"> as an actor. Hence, the
<:f200,QCourier New,>validActor<:f> method defined in adv.t applies to
<+">all<-"> objects, not just actors. This method is used in determining whether an object can be addressed by the player at all; if a head of lettuce is present in the same room, the player should be able to address it, even though doing so may not do any
good.
<+C><:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>For any object which passes the <:f200,QCourier New,>validActor<:f> test, the parser notes whether the object is a "preferred" actor, by calling the
<:f200,QCourier New,>preferredActor<:f> method on each object. This method returns
<:f200,QCourier New,>true<:f> if the object is generally suitable for use as an actor,
<:f200,QCourier New,>nil<:f> otherwise. The default definitions in adv.t return
<:f200,QCourier New,>true<:f> for this method for all objects of class Actor,
<:f200,QCourier New,>nil<:f> for other types of objects.
<+C><:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>After removing all objects that failed the <:f200,QCourier New,>validActor<:f> test, the parser looks at its list to see what's left.
<+C><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>If no objects remain, the player has tried to talk to something that is not currently accessible as an actor, or which doesn't exist at all. If none of the objects in the original list were visible, the parser issues error 9: "I don't see any %s here." (N
ote that the "%s" is replaced with the text of the player's noun phrase. So, if the original command was "Joe, Go West", the error message reads: "I don't see any joe here.") The reason the parser uses the player's original words in the error message is t
hat the parser can't determine what object the player is referring to--it can only use the words the player originally entered. Note that the parser always converts the player's words to lower-case.
<+C><:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>If more than one object remains, the parser goes back and looks at the results of the
<:f200,QCourier New,>preferredActor<:f> method for each object remaining. If any objects returned
<:f200,QCourier New,>true<:f> from this method, the parser considers only those objects; if all returned
<:f200,QCourier New,>nil<:f>, the parser ignores the <:f200,QCourier New,>preferredActor<:f> results and keeps the original list. If exactly one object returned
<:f200,QCourier New,>true<:f> from <:f200,QCourier New,>preferredActor<:f>, the parser uses that object as the actor. Otherwise, it must ask the player which of the remaining objects was intended; this process is the same as for any other object, and is des
cribed below.
<+C><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>If exactly one object remains, the parser uses that object as the actor. The process of determining the actor is completed.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624><:ZIdentVerb><:Z~IdentVerb>Identifying the Verb
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Once the actor (or absence of an actor) has been determined, the parser finds the verb. This is one of the simpler parts of parsing, because the verb must always be the first word of the command. The parser takes the first word and checks to make sure it ca
n be used as a verb; if not, message 17 ("There's no verb in that sentence!") is displayed, and the command is aborted.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>When you define a verb, you can specify one word or two. For example, the verb "take" is specified with a single word, whereas "pick up" is specified with two words. In English (and some other languages), a preposition can be associated with a verb in such
a way that it effectively becomes part of the verb--the preposition's presence changes the meaning of the verb so much that the verb-preposition combination is effectively a whole new verb: "throw away" has a meaning entirely different from "throw." TADS
supports this construct with two-word verbs. Note that when you define a two-word verb, the second word in the two-word verb must be separately defined as a preposition--the parser does not automatically create a preposition for the word. For example, a ver
b defined as "pick up" requires that the preposition "up" be defined as well (these particular examples are defined in adv.t).
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>If the word following the verb is defined as a preposition, the parser checks to see if it's defined as part of a two-word verb with the verb in the sentence. If it is, the parser takes the pair of words as the verb--if the player types "pick up" as the fir
st two words of a command, the parser takes the pair as the verb-preposition combination. If the preposition does
<+">not<-"></`>go with the verb, and the same word can be used as a noun or an adjective, the parser takes the verb to be the first word of the command only, and assumes the second word is being used as part of a noun phrase.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Once the verb is identified as the first one or two words of the sentence, the parser checks to see if anything remains. If the next word is a sentence separator ("and" or a comma), or if no more words follow, the parser takes it as the end of the sentence,
and executes the verb without any objects.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If the next word starts a noun phrase, the reads the noun phrase that follows, and then checks to see what follows that. If the next word is a sentence separator, the parser takes it as the end of the sentence, and executes the verb with the noun phrase as
the direct object.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If, instead, the next word is a preposition, the parser checks what follows the preposition. If the next word starts another noun phrase, the parser reads this second noun phrase, then executes the command with both a direct and an indirect object, with th
e preposition separating them.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>If the word following the preposition is a sentence separator, the parser takes the preposition as part of the verb. With verb-preposition combinations, the preposition is sometimes placed immediately after the verb, as in "pick up the book," but can also b
e put at the end of the sentence, as in "pick it up." So, if the parser finds a preposition at the end of the sentence, it treats the preposition the same way it would have if the preposition had immediately followed the verb.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3549,6624>Note that many of these cases can be ambiguous--based on the parts of speech of the words in a sentence, more than one interpretation is possible. The parser's rules as described above are designed to choose the most sensible interpretation, but sometimes t
he results will not be exactly what you may have intended. For example, if your game has an object defined as an "up button" (in an elevator, for example), the word "up" will end up defined as a verb, preposition, and adjective. If the player types "push u
p button," and no verb is defined as "push up," the parser will know that "push" and "up" don't go together as a verb and will interpret this as applying the verb "push" to the object "up button." However, if the player types "pick up button," the parser w
ill interpret this as applying the verb "pick up" to the object "button"; if you also have a down button, the parser will ask the player which button to take--which would be confusing if the player had intended to apply the verb "pick" to the object "up but
ton."
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Ambiguous word definitions are very difficult to anticipate, because there are so many possible combinations of words in even a small game. The best way to find these is to test your game, and have other people test it.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that in the course of identifying the verb, the parser has also identified the noun phrases that make up the direct and indirect objects, and the preposition that separates the direct and indirect objects. For the command "open the door and the window,
" the parser identifies the following sentence components:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>actor: Me
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>verb: open
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>direct object: the door and the window
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>For the command "joe, pick up the ball with the tongs," the parser will identify the following elements:
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>actor: Joe
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>verb: pick up
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>direct object: the ball
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>preposition: with
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>indirect object: the tongs
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624><:ZNounPhrases><:Z~NounPhrases>Noun Phrases and Objects
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>A noun phrase is made up of an optional article, one or more optional adjectives, a noun or a plural, and optionally the word "of" (or an equivalent defined with
<:f200,QCourier New,>specialWords<:f>) and another noun phrase. A word is a noun if it matches a word defined in the
<:f200,QCourier New,>noun<:f> property of an object in your game; likewise for adjectives, plurals, and articles.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Certain special words can be used as noun phrases. The word "all" is by itself a valid noun phrase, as are the pronouns (it, him, her, and them). "All" or "all of" followed by a plural noun phrase (which is a noun phrase whose last word is a plural rather t
han a noun) is a noun phrase, equivalent to the plural noun phrase without the "all" or "all of." Similarly, "both" and "both of" can be used in exactly the same way. "Any" followed by a noun phrase, or "any of" followed by a plural noun phrase, can also b
e used; these tell the parser to arbitrarily pick one of the objects indicated.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The player can also specify a count with a plural or with "any." For example, phrases such as "3 books," "any 3 books," "3 of the books," and "any 3 of the books" work the same as "any book," but the parser will (arbitrarily) choose three of the named obje
cts in this case, rather than just one. If the number is "1," the parser allows this format with a singular noun phrase as well: "1 book" or "any 1 book," which are equivalent to "any book."
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The player can also use multiple noun phrases, by separating each with "and" or a comma.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>During the first phase of parsing, before starting to execute the command, the parser identifies
<+">all<-"> of the possible objects for each noun phrase. After finding the words involved in the noun phrase (which is done entirely on the basis of their defined parts of speech, as described above), the parser makes a list of all of the objects which mat
ch all of the words in the noun phrase. For example, if the noun phrase is "pile of red paper," the parser finds every object which has "pile" defined as a noun, "red" defined as an adjective, and "paper" defined as a noun. The parser intersects these lists
of objects to arrive at a list of objects that have all three words defined.
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>In most circumstances, a number entered as part of a command serves as a noun, and is assigned to
<:f200,QCourier New,>numObj<:f> (see the section on object resolution on page
<:X3,-16384;PageRef ObjectResolution>94<:X~3,-16384;PageRef ObjectResolution>). In some cases, though, you may want to use a number as part of the name of an object. For example, you might have a five dollar bill, in which case you would want "5" to serve
as an adjective for the object. Similarly, if you have an elevator with a button for each floor, the buttons will be called "button 3," and so on.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>The parser allows you to enter numbers as adjectives. For example:
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>When a number is defined as an adjective, and the object is present, the parser allows the number to be used as either a prefix or a suffix in the noun phrase: "button 3" and "3 button" (as well as "three button") are valid noun phrases referring to the bu
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Command Execution: Part One
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>Now that the command has been identified, the parser begins to execute it.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The first step in execution is to call a user function called <:f200,QCourier New,>preparseCmd<:f>. This functional is optional; if your game doesn't define one, the parser skips this step. The parser calls the function with a single parameter: a list of (
single-quoted) strings, one string per word in the command. For example, for the command "open the door and the window," the parser calls the function like this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Note that the word "and" became a comma. "And," and certain other words, are transformed internally before this function is called:
<+@><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#245,6624><:f200,,> and <:f180,rZapfDingbats,><\]><:><:><:f180,rZapfDingbats,> <:f200,,>,
<+@><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#245,6624><:f200,,> all <:f180,rZapfDingbats,><\]><:><:><:f180,,> <:f200,,>A
<+@><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#245,6624><:f200,,> but <:f><:f180,rZapfDingbats,><\]><:f><:><:><:f180,,> <:f200,,>X
<+@><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#245,6624><:f200,,> it <:f><:f180,rZapfDingbats,><\]><:f><:><:><:f180,,> <:f200,,>I
<+@><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#245,6624><:f200,,> them <:f><:f180,rZapfDingbats,><\]><:f><:><:f180,,> <:f200,,>T
<+@><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#245,6624><:f200,,> him <:f><:f180,rZapfDingbats,><\]><:f><:><:f180,,> <:f200,,>M
<+@><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#245,6624><:f200,,> her <:f><:f180,rZapfDingbats,><\]><:f><:><:f180,,> <:f200,,>R
<+@><:I0,360,0,0><:S+-1><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#245,6624><:f200,,> any <:f><:f180,rZapfDingbats,><\]><:f><:><:f180,,> <:f200,,>Y<:f>
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Your <:f200,QCourier New,>preparseCmd<:f> function can return one of three values:
<:f200,QCourier New,>true<:f>, <:f200,QCourier New,>nil<:f>, or a list. If the function returns
<:f200,QCourier New,>true<:f>, processing continues as normal. If it returns
<:f200,QCourier New,>nil<:f>, the command is abandoned--the parser discards the current command, and goes back to the beginning of the parsing process to get a new command. If the function returns a list, the list must consist entirely of single-quoted stri
ngs; the parser will go back to the step described above under "Checking for an Actor," substituting the returned list for the original command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Note that the argument to <:f200,QCourier New,>preparseCmd<:f> doesn't include the actor specification. For example, if the player types "joe, go west,"
<:f200,QCourier New,>preparseCmd<:f> will receive only "go west." In addition, the list doesn't include the words separating the command from the previous or next command on the same line. For example, if the player types "go west, then pick up the box," t
he function is called first with simply "go west," then with "pick up the box."
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>In addition, this command is called for each command just prior to the steps described below. For example, if the player types "go west, then pick up the box," the parser first calls
<:f200,QCourier New,>preparseCmd<:f> with "go west," and then proceeds through the rest of the processing for this command as described below; after that's all done, the parser comes back to this step, calls
<:f200,QCourier New,>preparseCmd<:f> with "pick up the box," and then proceeds through the steps below once again.
<:s><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The <:f200,QCourier New,>preparseCmd<:f> function is allowed to change a particular command only once. If
<:f200,QCourier New,>preparseCmd<:f> returns a list value, the parser goes back and starts processing the list as a new command--as a result, the new command will itself be submitted to
<:f200,QCourier New,>preparseCmd<:f> when the parser gets back to this step. On this second call,
<:f200,QCourier New,>preparseCmd<:f> is not allowed to return a list; if it does, the parser displays an error that indicates the
<:f200,QCourier New,>preparseCmd<:f> appears to be stuck in a loop (message 402) and cancels the command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Here's a sample implementation of <:f200,QCourier New,>preparseCmd<:f>. This implementation converts commands in the format "tell
<+">actor<-"></`>to <+">command<-">" to the standard TADS notation for these commands, "<+">actor<-">,
<:I0,432,0,0><:R1,14,1,792,1,1174,1,1512,1,1862,1,2160,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> local i, tot, to_loc, actor, the_rest;
<:s><:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624> <:f200,QCourier New,>/* see if there's a "to" */<:f>
<:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624> <:f200,QCourier New,>for (i := 1, tot := length(cmd) ;
<:s><:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> i <<= tot ; ++i)
<:s><:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> <:f><:f200,QCourier New,>/* check for TELL actor TO command */
<:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (tot <;>= 1 and cmd<[>1] = 'tell' and
<:s><:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> /* get the actor */
<:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> for (i := 2, actor := <[>]
<:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> ; i << to_loc ; ++i)
<:s><:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> /* get the command */
<:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> for (the_rest := <[>],<:f><:f200,QCourier New,>i := to_loc+1 ;
<:s><:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> i <<= tot ; ++i)
<:s><:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> /* change it to "actor, command" */
<:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> return actor + ',' + the_rest;
<:s><:I0,432,0,0><:R1,14,1,792,1,1152,1,1512,1,1862,1,2232,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> /* process the command unchanged */
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>After <:f200,QCourier New,>preparseCmd<:f> returns true, the parser makes sure it has a valid
<:f200,QCourier New,>deepverb<:f> object for the verb phrase. If no object is found that defines the verb phrase as one of its
<:f200,QCourier New,>verb<:f> property values, the parser displays an error (message 18, "I don't understand that sentence") and cancels the commands.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Next, the parser runs the <:f200,QCourier New,>roomCheck<:f> method in the object
<:f200,QCourier New,>Me<:f>. The <:f200,QCourier New,>roomCheck<:f> method is called with a single argument: the
<:f200,QCourier New,>deepverb<:f> object. For example, if the player types "take book," the parser calls this method:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>This method should return either <:f200,QCourier New,>true<:f> or
<:f200,QCourier New,>nil<:f>: a return value of <:f200,QCourier New,>true<:f> indicates that the command is allowed to proceed. If
<:f200,QCourier New,>roomCheck<:f> returns <:f200,QCourier New,>nil<:f>, the command is canceled. The
<:f200,QCourier New,>roomCheck<:f> method is expected to display a message indicating why the command is not allowed, so the parser doesn't display any additional information when
<:f200,QCourier New,>roomCheck<:f> returns <:f200,QCourier New,>nil<:f>--it simply cancels the command without further comment.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>The <:f200,QCourier New,>roomCheck<:f> method is intended to be a first, coarse check of whether a command is valid in a room. This method is called prior to any disambiguation, and once for the entire command (regardless of how many direct objects may be i
nvolved in the command). The main use of this method is to disallow entire verbs in a room based on the room's condition; for example, you could use
<:f200,QCourier New,>roomCheck<:f> to prevent the player from being able to take any objects while in the dark. Since this method is called prior to disambiguation, you can prevent the disambiguation process from displaying any information about the room th
at the player should not be able to see.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>The default <:f200,QCourier New,>roomCheck<:f> defined in the <:f200,QCourier New,>basicMe<:f> class in adv.t simply returns the value of the
<:f200,QCourier New,>roomCheck<:f> method in the player's location. (The
<:f200,QCourier New,>roomCheck<:f> defined in the <:f200,QCourier New,>movableActor<:f> class does the same thing for the actor's location.) The
<:f200,QCourier New,>roomCheck<:f> defined in the <:f200,QCourier New,>room<:f> class in adv.t always returns
<:f200,QCourier New,>true<:f>, and the <:f200,QCourier New,>roomCheck<:f> defined in the
<:f200,QCourier New,>darkroom<:f> class in adv.t returns <:f200,QCourier New,>nil<:f> unless the location is lit, or the verb is a "dark verb" (i.e., its
<:f200,QCourier New,>isDarkVerb<:f> property is <:f200,QCourier New,>true<:f>), which means that it can be used in the dark. All "system" verbs (such as "save" and "restore"), as well as a few other verbs that don't logically require light (such as "wait"),
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The parser must now determine how to execute the command. The first step is to identify the
<:f200,QCourier New,>deepverb<:f> object associated with the word or words making up the verb; to do this, the parser simply looks up the verb phrase in its dictionary, and finds the object that defined the phrase as one of its
<:f200,QCourier New,>verb<:f> property values.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>A single <:f200,QCourier New,>deepverb<:f> can have multiple interpretations; these interpretations are called "templates," because they serve as models for the possible sentences that can be made with the verb.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>TADS verb templates are a subtle concept, because templates are not explicitly stated in a
<:f200,QCourier New,>deepverb<:f>; rather, they are <+">implied<-"> by the presence of the properties
<:f200,QCourier New,>action<:f>, <:f200,QCourier New,>doAction<:f>, and
<:f200,QCourier New,>ioAction<:f>. If an <:f200,QCourier New,>action<:f> method exists for the verb, the template sentence that consists only of the verb is implicitly defined. If a
<:f200,QCourier New,>doAction<:f> property exists for the verb, the template sentence that consists of the verb and a direct object is implicitly defined. If an
<:f200,QCourier New,>ioAction<:f> property is defined for a particular preposition object, the verb implicitly defines the template sentence that consists of the verb, a direct object, the specified preposition, and an indirect object.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>The "wait" verb defined in adv.t defines only the no-object template:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>The "lock" verb defined in adv.t defines both a one-object and two-object template, but doesn't have a no-object template:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Note that the <:f200,QCourier New,>ioAction<:f> definition can contain certain special flags that affect the way commands matching the template are processed. For example, you could define a template as follows:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>The <:f200,QCourier New,><[>disambigDobjFirst]<:f> flag (which is the only flag currently defined) specifies that the parser is to disambiguate the direct object first when a sentence involving this template is executed. Normally, the parser disambiguates
the indirect object first, then disambiguates the direct object with the indirect object known. For some commands this is undesirable, because it means that the direct object isn't known when the indirect object is being disambiguated. This flag provides
control over the sequence of disambiguation, so that you can determine which object is known first, which allows you to use that object while disambiguating the other.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>To choose a template, the parser uses the components of the command, which were determined earlier (see the section "Identifying the Verb" on page
<:X3,-16384;PageRef IdentVerb>78<:X~3,-16384;PageRef IdentVerb>). If the only non-empty component of the command is the verb, the parser chooses the no-object template; if the
<:f200,QCourier New,>deepverb<:f> defines an <:f200,QCourier New,>action<:f> method, it has a no-object template, and therefore allows no-object sentences.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>If the sentence has a verb and a direct object, but no preposition or indirect object, the parser chooses the one-object template. If the
<:f200,QCourier New,>deepverb<:f> has a <:f200,QCourier New,>doAction<:f> property, the verb has a one-object template, and thus allows single-object sentences. The
<:f200,QCourier New,>doAction<:f> property specifies the verification and action methods for the command: TADS appends the string defined by
<:f200,QCourier New,>doAction<:f> to the string "verDo" to form the verification method, and "do" to form the action method. For example, if
<:f200,QCourier New,>doAction<:f> <:f200,QCourier New,>= 'Take'<:f>, the verification method is called
<:f200,QCourier New,>verDoTake<:f>, and the action method is called
<:f200,QCourier New,>doTake<:f>.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>If the sentence has a verb, direct object, preposition, and direct object, the parser uses a two-object template. A single
<:f200,QCourier New,>deepverb<:f> object can define multiple two-object templates; these multiple templates are distinguished from one another by their prepositions. The templates are defined by the
<:f200,QCourier New,>ioAction<:f> property--each <:f200,QCourier New,>ioAction<:f> specifies the preposition which identifies it. If the player types "dig in dirt with shovel," the parser looks in
<:f200,QCourier New,>digVerb<:f> for an <:f200,QCourier New,>ioAction(withPrep)<:f> definition. (Note that
<:f200,QCourier New,>digVerb<:f>. and <:f200,QCourier New,>withPrep<:f> could actually be called anything--we're following the naming conventions used in adv.t here, but you can call verb and preposition objects anything you want. The parser doesn't identif
y these objects based on their names, but rather based on their vocabulary words, defined by their
<:f200,QCourier New,>verb<:f> and <:f200,QCourier New,>preposition<:f> properties, respectively.)
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The parser must now match the components of the sentence entered by the player with the templates available for the verb. Before going on, the parser checks to make sure that the verb object is properly defined: it must define at least one sentence templat
e. If the <:f200,QCourier New,>deepverb<:f> object fails to define any templates (that is, it has no
<:f200,QCourier New,>action<:f>, <:f200,QCourier New,>doAction<:f>, or
<:f200,QCourier New,>ioAction<:f> properties), the parser displays an error (message 23) and cancels the command.
<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Case 1: A Command with No Objects<-!>
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>If the player's command has no objects at all, but consists only of a verb, the parser checks to see if the
<:f200,QCourier New,>deepverb<:f> has an <:f200,QCourier New,>action<:f> method; if so, the parser chooses the verb-only sentence template and proceeds with the execution.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>If the command has no objects, and the <:f200,QCourier New,>deepverb<:f> object does
<+">not<-"> define an <:f200,QCourier New,>action<:f> method, the parser tries to provide a default direct object by calling the
<:f200,QCourier New,>doDefault<:f> (which stands for "direct-object default") method in the
<:f200,QCourier New,>deepverb<:f> object. This method is called with the actor, the preposition, and
<:f200,QCourier New,>nil<:f> (since the indirect object is not yet known) as arguments. For example, if the player types simply "pick up," the parser chooses
<:f200,QCourier New,>takeVerb<:f> as the <:f200,QCourier New,>deepverb<:f> object, sees that it has no
<:f200,QCourier New,>action<:f> property, so attempts to obtain a default object:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>This method is meant to return a list of objects that should be used by default for the command; the definition of this method for the
<:f200,QCourier New,>takeVerb<:f> defined in adv.t returns a list of all movable objects in the player's location. If this method fails to return a list, the parser simply asks the player to supply a direct object (see below). Otherwise, the parser now gets
the value of the <:f200,QCourier New,>prepDefault<:f> property in the
<:f200,QCourier New,>deepverb<:f> object: if this value is not <:f200,QCourier New,>nil<:f>, it must refer to a preposition object, which becomes the preposition for the command.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>For example, if the player simply types "dig," the parser gets the default list from the
<:f200,QCourier New,>doDefault<:f> method defined in <:f200,QCourier New,>digVerb<:f>, then gets the value of
<:f200,QCourier New,>digVerb.prepDefault<:f>. Suppose that <:f200,QCourier New,>prepDefault<:f> has a value of
<:f200,QCourier New,>withPrep<:f>: the command's components now look like this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>actor: Me
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>direct object: (the list returned by <:f200,QCourier New,>doDefault<:f>)
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>preposition: with
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>indirect object: <:f200,QCourier New,>nil<:f> (because it's not yet known)
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The parser checks that the template specified by the new components exists for the verb. If it doesn't, the parser skips checking the
<:f200,QCourier New,>doDefault<:f> return value, and goes on to ask for a direct object.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>If a valid list resulted from <:f200,QCourier New,>doDefault<:f>, and the new template is valid, the parser goes through the
<:f200,QCourier New,>doDefault<:f> list to check each item with the direct object verification method defined by the
<:f200,QCourier New,>doAction<:f> or <:f200,QCourier New,>ioAction<:f> method for the new template. If the template is a single-object sentence, which means that the
<:f200,QCourier New,>doAction<:f> definition is used, the parser calls the verification method with the actor as a parameter. If the template is for a two-object sentence, which means that the
<:f200,QCourier New,>ioAction<:f> definition is used, the parser calls the verification method with the actor and
<:f200,QCourier New,>nil<:f> (because the indirect object is not yet known) as parameters. If the
<:f200,QCourier New,>ioAction<:f> is used, but the <:f200,QCourier New,>ioAction<:f> template specifies the
<:f200,QCourier New,><[>disambigDobjFirst]<:f> flag, the second (<:f200,QCourier New,>nil<:f>) parameter is omitted. Some examples:
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>In this third example, we're assuming that <:f200,QCourier New,>tellVerb<:f>'s
<:f200,QCourier New,>ioAction<:f> property has the <:f200,QCourier New,><[>disambigDobjFirst]<:f> flag.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The verification methods are called silently, which means that any messages they display are hidden from the user (the same as during the disambiguation process). However, the parser notes whether these methods attempt to display any messages; any verifica
tion method that attempts to display a message is considered to fail. The parser discards any objects from the list whose verification method fails.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>If exactly one object from the <:f200,QCourier New,>doDefault<:f> list passes the silent verification test, that object is chosen as the default direct object for the command. The parser displays the object to the player: if your game program defines the
function <:f200,QCourier New,>parseDefault<:f>, the parser calls this function with the chosen default object as the parameter, and expects that the function will display a message to indicate that the object has been chosen as the default. Otherwise, the
parser displays message 130 ("("), then calls the method <:f200,QCourier New,>thedesc<:f> in the default object, then displays message 131 (")"). It then starts this step over again with the new set of command components.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Here's a sample implementation of <:f200,QCourier New,>parseDefault<:f>. This definition generates the same message that the parser would if
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>If no objects survive the verification test, the parser doesn't have any way to supply a default object. If more than one object survives, the parser still does not supply a default object, because the command doesn't imply a specific object. In either ca
se, the parser now asks the player to supply a direct object; see the description below.
<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Case 2: A Command with One Object<-!>
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>If the player's command has a direct object, but no preposition or indirect object, the parser checks the verb for a single-object sentence template. If the
<:f200,QCourier New,>deepverb<:f> object has a <:f200,QCourier New,>doAction<:f> property, the single-object sentence is allowed. The parser first disambiguates the direct object list (see the section on resolving objects on page
<:X3,-16384;PageRef ObjectResolution>94<:X~3,-16384;PageRef ObjectResolution>). If this succeeds, the parser saves the direct object (or list of direct objects) for future use as "it" or "them" (or "him" or "her," if appropriate), and proceeds to execute t
he command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>If a single-object sentence is not allowed, the parser checks the
<:f200,QCourier New,>prepDefault<:f> property of the <:f200,QCourier New,>deepverb<:f> object; if it's
<:f200,QCourier New,>nil<:f>, the sentence is not allowed, so the parser displays message 24 ("I don't recognize that sentence") and terminates the current command. Otherwise, the parser uses the
<:f200,QCourier New,>prepDefault<:f> value as the preposition for the command, and calls the
<:f200,QCourier New,>ioDefault<:f> method of the <:f200,QCourier New,>deepverb<:f> with the actor and preposition as arguments. For example, if the player types "put ball," and the verb has a default preposition of "in," the parser calls
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>If this method returns something other than a list, the parser ignores it, and asks the player to supply an indirect object (see below). Otherwise, the parser checks to see if the direct object must be disambiguated prior to the indirect object--if the
<:f200,QCourier New,>ioAction<:f> property defines the <:f200,QCourier New,><[>disambigDobjFirst]<:f> flag, the direct object must be disambiguated first. If so, the parser disambiguates the direct object using the normal process (see the section on disamb
iguation on page <:X3,-16384;PageRef ObjectResolution>94<:X~3,-16384;PageRef ObjectResolution>). Next, the parser goes through the
<:f200,QCourier New,>ioDefault<:f> list, and silently calls the verification method for each object. For normal verbs, these calls look like this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>When the <:f200,QCourier New,>ioAction<:f> property has the <:f200,QCourier New,><[>disambigDobjFirst]<:f> flag, these calls look like this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>These calls are made silently--any messages they display are hidden from the player. However, the parser notes whether they attempt to display anything; any verification method that attempts to display a message is considered to have failed. The parser re
moves from the <:f200,QCourier New,>ioDefault<:f> any objects whose verification method fails at this point.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#4095,6624>If exactly one object survives this test, the parser uses this object as the default indirect object and proceeds with the command. First, though, it shows the player that the object is being assumed. If your game defines a function called
<:f200,QCourier New,>parseDefault<:f>, the parser calls this function with the verb and the preposition as arguments. Note that you must define
<:f200,QCourier New,>parseDefault<:f> to take a variable argument list, because it can be called with either one or two arguments: when called with one argument, it means that the a default direct object is being assumed; when called with two arguments, it
means that a default indirect object is being assumed. Note further that the preposition supplied as the second argument can be
<:f200,QCourier New,>nil<:f>, which will be the case when a two-object command is entered that has no preposition (for example: "give joe the bottle"). If your game doesn't define a
<:f200,QCourier New,>parseDefault<:f> function, the parser generates a message by displaying message number 130 ("("), then calling the preposition object's
<:f200,QCourier New,>sdesc<:f> method, then displaying message 132 (a space), then calling the default indirect object's
<:f200,QCourier New,>thedesc<:f> method, and then displaying message 131 (")").
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If no objects survive the verification test, the parser can't supply a default indirect object. If more than one object survives, the parser doesn't supply a default indirect object, because the command doesn't imply a particular object. In either case, t
he parser asks the player to supply an indirect object (see below).
<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Case 3: A Command with Two Objects<-!>
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>If the player specifies a command with two objects and no preposition, the parser treats the first object as the indirect object, and the second as the direct object, and uses the two-object sentence format. When this type of sentence is entered, the parse
r gets the value of the <:f200,QCourier New,>deepverb<:f> object's
<:f200,QCourier New,>nilPrep<:f> property--this property should return a preposition object that is to be used for a sentence of this type. If
<:f200,QCourier New,>nilPrep<:f> doesn't return a preposition object, the parser assumes that the preposition is "to," and finds the preposition object with that vocabulary word. In any case, the parser transforms the sentence from the format VERB IOBJ DOB
J to the standard two-object sentence format, VERB DOBJ PREP IOBJ, then proceeds with the command as though it had been entered that way in the first place.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>If the player enters a command in the format VERB PREP OBJ1 OBJ2, the parser converts this to VERB OBJ2 PREP OBJ1--in other words, the original sentence is interpreted as VERB PREP IOBJ DOBJ. After the conversion, the parser proceeds with the sentence as t
hough it had originally been entered as VERB DOBJ PREP IOBJ. This conversion is most useful for some non-English languages; English speakers don't typically use this construction.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If the player specifies a command with a preposition and one or two objects, the parser finds the
<:f200,QCourier New,>ioAction<:f> definition that matches the given preposition. If the verb doesn't have an appropriate
<:f200,QCourier New,>ioAction<:f> property, the parser displays message 24 ("I don't understand that sentence"), and abandons the command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>If only one object was provided, the parser takes the object that was given as the indirect object, and attempts to find a direct object. The parser uses the same mechanism to find the direct object--first by trying to find a default direct object, then by
asking the player--as described above in Case 1. This type of sentence is useful when the
<+">direct<-"></`>object is implied by the verb; for example, if a single actor is present in the room with the player, the direct object of "ask about the murder" would implicitly be the actor.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>If two objects are provided, the parser disambiguates the two objects. If the
<:f200,QCourier New,>ioAction<:f> has the <:f200,QCourier New,><[>disambigDobjFirst]<:f> flag, the parser disambiguates the direct object first; otherwise, it disambiguates the indirect object first. It then disambiguates the other object. See the section
on resolving objects (page <:X3,-16384;PageRef ObjectResolution>94<:X~3,-16384;PageRef ObjectResolution>) for details.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>The parser never allows a command to use multiple indirect objects. If the command contains more than one indirect object, the parser displays message 25 ("You can't use multiple indirect objects") and abandons the command. When the direct object is disam
biguated first (which will happen only when the <:f200,QCourier New,>ioAction<:f> has the
<:f200,QCourier New,><[>disambigDobjFirst]<:f> flag), the parser also restricts the direct object to a single object; if multiple direct objects are specified in this case, the parser displays message 28 ("You can't use multiple objects with this command")
and abandons the command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Once the objects have been disambiguated, the parser saves the direct object or objects as "it" or "them" (or "him" or "her," as appropriate), then executes the command.
<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Asking for an Object<-!>
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If the verb requires a direct or indirect object, but the command doesn't specify one and the parser can't find a suitable default, the parser must ask the player to supply an object for the command. First, it must display a message asking for the object.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3549,6624>To do this, the parser checks to see if your game program defines a function called
<:f200,QCourier New,>parseAskobjActor<:f>; if so, it calls this function with the actor as the first argument, the
<:f200,QCourier New,>deepverb<:f> object as the second argument, and the preposition as an optional third argument--this third argument is present only if an indirect object is required, and even then may be
<:f200,QCourier New,>nil<:f>. Your <:f200,QCourier New,>parseAskobjActor<:f> function is expected to display a message asking the player to supply a direct object for the verb. (Note that if you don't define a
<:f200,QCourier New,>parseAskobjActor<:f> function, but you <+">do<-"></`>define a function called
<:f200,QCourier New,>parseAskobj<:f>, the function <:f200,QCourier New,>parseAskobj<:f> will be called instead.
<:f200,QCourier New,>parseAskobj<:f> has the same purpose as <:f200,QCourier New,>parseAskobjActor<:f>, but does not receive the actor as a parameter.
<:f200,QCourier New,>parseAskobj<:f> is called for compatibility with games written prior to version 2.2; you should use
<:f200,QCourier New,>parseAskobjActor<:f> for new games, since this function gives you more information.)
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Note that the <:f200,QCourier New,>parseAskobjActor<:f> function is called with a third argument only when the parser is asking for an indirect object. The third argument is the preposition object, which may be
<:f200,QCourier New,>nil<:f>. Because the parser calls <:f200,QCourier New,>parseAskobjActor<:f> with two
<+">or<-"> three arguments, depending on whether it's asking for a direct or indirect object, your
<:f200,QCourier New,>parseAskobjActor<:f> function must be defined as taking variable arguments. You can determine if the function is being called with two or three arguments by inspecting the
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>If your game does not have a <:f200,QCourier New,>parseAskobjActor<:f> (or
<:f200,QCourier New,>parseAskobj<:f>) function, the parser generates its own message. If no actor (other than
<:f200,QCourier New,>Me<:f>) is specified in the command, the parser displays message 140 ("What do you want to"); if an actor is specified, the parser displays message 148 ("What do you want"), then calls the actor's
<:f200,QCourier New,>thedesc<:f> method, then displays message 149 ("to"). Next, the parser calls the
<:f200,QCourier New,>sdesc<:f> method in the <:f200,QCourier New,>deepverb<:f> object. If an indirect object is required, the parser next displays an appropriate pronoun for the direct object, then calls the preposition's
<:f200,QCourier New,>sdesc<:f> method (if the preposition is <:f200,QCourier New,>nil<:f>, the parser displays message 142, "to"). Finally, the parser displays message 143 ("?").
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Here's a sample definition of <:f200,QCourier New,>parseAskobjActor<:f>, which generates the same prompt that the parser would if
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "What do you want ";
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (a <<<;> Me) a.thedesc;
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> <:f><:f200,QCourier New,>" to <<<<v.sdesc<;><;> <<<<<:f><:f200,QCourier New,>getarg(3<:f><:f200,QCourier New,>).sdesc<;><;> it?";
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "What do you want ";
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (a <<<;> Me) a.thedesc;
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>If a pronoun for the direct object is required, the parser checks each object in the direct object list. If the player explicitly specified multiple direct objects (by using "all" or a list of noun phrases), the parser displays message 144 ("them"). Other
wise, if every object in the list returns consistent values from <:f200,QCourier New,>isHim<:f> and
<:f200,QCourier New,>isHer<:f>, the parser displays message 147 ("them") if all objects return
<:f200,QCourier New,>true<:f> for <+">both<-"></`><:f200,QCourier New,>isHim<:f> and
<:f200,QCourier New,>isHer<:f>; message 145 ("him") if only <:f200,QCourier New,>isHim<:f> returned
<:f200,QCourier New,>true<:f>; message 146 ("her") if only <:f200,QCourier New,>isHer<:f> returned
<:f200,QCourier New,>true<:f>; or message 141 ("it") if neither <:f200,QCourier New,>isHim<:f> nor
<:f200,QCourier New,>isHer<:f> were <:f200,QCourier New,>true<:f> for all objects.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>After displaying a message (either with <:f200,QCourier New,>parseAskobjActor<:f> or through a set of messages as described above), the parser allows the user to enter a new command, using
<:f200,QCourier New,>commandPrompt<:f> code 3 if asking for a direct object and code 4 for an indirect object. If the new command appears to consist only of a noun phrase, the parser uses that noun phrase for the missing object, and goes back to the beginn
ing of this step to process the command with the new noun phrase filling in the missing component. Note that the player can use anything in this noun phrase that would have been allowed in the command itself, including multiple objects and special words su
ch as "all."
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If the new command does not appear to consist of only a noun phrase, the parser abandons the current command and starts over from the beginning with the new command. So, when the parser asks the player to supply an object, the player can choose either to a
nswer the question, or to type a brand new command.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624><:ZObjectResolution><:Z~ObjectResolution>Resolving the Objects
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>After the parser has made a final determination of the form of the sentence, and identified the verb template, it must resolve the noun phrases in the command to game objects. Up to this point, the parser has been keeping a list of the objects matching eac
h noun phrase; these lists include all objects in the <+">entire game<-"></`>that match each noun phrase. At this point, the parser must determine which specific object or objects the player meant for each noun phrase. This process is called "resolving" o
r "disambiguating" the object references.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Certain special noun phrases can be resolved with very little work. The player can include a string enclosed in double quotes in a command:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>type "hello, world!" on the terminal
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Strings are always mapped to the special object <:f200,QCourier New,>strObj<:f>, which must be supplied by your game program (adv.t provides a class called
<:f200,QCourier New,>basicStrObj<:f>, which provides a suitable definition that you can use a superclass of your own
<:f200,QCourier New,>strObj<:f> object). In this case, the parser uses
<:f200,QCourier New,>strObj<:f> as the direct object to the command, and sets the
<:f200,QCourier New,>value<:f> property of <:f200,QCourier New,>strObj<:f> to the (single-quoted) string value
<:f200,QCourier New,>'hello, world!'<:f>.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>Likewise, the player can use numbers:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><;>dial 8056 on the phone
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Numbers are mapped to the special object <:f200,QCourier New,>numObj<:f>; as with
<:f200,QCourier New,>strObj<:f>, this must be supplied by your game (adv.t provides a
<:f200,QCourier New,>basicNumObj<:f> class). In this example, the direct object will be
<:f200,QCourier New,>numObj<:f>, and its <:f200,QCourier New,>value<:f> property will be set to the numeric value 8056.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>The special words for the pronouns (it, them, him, and her) are taken from the direct object of the previous command. (Note that you can also set the meaning of the pronouns from within game code, using the
<:f200,QCourier New,>setit()<:f> built-in function. When you don't use
<:f200,QCourier New,>setit()<:f> to set the pronouns yourself, the system will automatically set the pronouns to the direct object of the previous command.) Before accepting the pronoun, the system uses the access-checking function (<:f200,QCourier New,>va
lidDo<:f> for a direct object, <:f200,QCourier New,>validIo<:f> for an indirect object) to ensure that the object is still accessible.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The special word for "all" is replaced with the object list returned by the
<:f200,QCourier New,>doDefault<:f> property of the verb. The parser calls
<:f200,QCourier New,>doDefault<:f>, and includes all of the objects from the resulting list in the direct object list. If a list of objects is excluded with "but" (for example: "take everything except the key and the idol"), the parser removes the objects
in the exception list from the <:f200,QCourier New,>doDefault<:f> list.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Ordinary noun phrases require more analysis. In particular, we must identify the actual objects to which the noun phrases refer.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3549,6624>First, we identify which objects are accessible. To do this, the parser calls
<:f200,QCourier New,>validDoList<:f> (or <:f200,QCourier New,>validIoList<:f>, as appropriate) in the
<:f200,QCourier New,>deepverb<:f>. This method is called with the actor, preposition, and other object as parameters; the preposition will be
<:f200,QCourier New,>nil<:f> for one-object commands, and the other object may be
<:f200,QCourier New,>nil<:f> if it's not known yet or isn't appropriate (when calling
<:f200,QCourier New,>validDoList<:f> for a one-object command, the other object will always be
<:f200,QCourier New,>nil<:f>). This method returns either a list of objects, or
<:f200,QCourier New,>nil<:f>; if it returns a list, this list is intersected with the list of objects that the parser found for the noun phrase, otherwise the entire noun phrase object list is retained. Note that
<:f200,QCourier New,>validDoList<:f> and <:f200,QCourier New,>validIoList<:f> must return every valid object, but they need not return
<+">only<-"> valid objects--since the remaining objects will be checked for validity with
<:f200,QCourier New,>validDo<:f> or <:f200,QCourier New,>validIo<:f>,
<:f200,QCourier New,>validDoList<:f> and <:f200,QCourier New,>validIoList<:f> can harmlessly include invalid objects in their results.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3822,6624>Next, we call <:f200,QCourier New,>validDo<:f> (or <:f200,QCourier New,>validIo<:f>) in the
<:f200,QCourier New,>deepverb<:f> for each surviving object. The arguments to this method are the actor, the object whose validity is being tested, and a "sequence number." The sequence number starts off at 1, and is incremented for each object in the lis
t. The sequence number can be used when you wish to arbitrarily select a single object from a list of ambiguous objects--simply return
<:f200,QCourier New,>true<:f> only for the first object, and <:f200,QCourier New,>nil<:f> for all of the other objects. If this method returns
<:f200,QCourier New,>true<:f>, it means that the object is valid for the current command--in other words, the object is accessible to the actor for the purposes of the command. If the player wishes to take an object, for example, the object should be valid
for the command if and only if the player can reach the object. For other commands, accessibility may not necessitate that the object is reachable; for example, to look at an object, it need only be visible--if the object is inside a locked glass case, it
will be visible but not reachable. The parser eliminates from consideration any objects for which
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>We now check each surviving object to see if it's logical with the verb. To do this, we make a "silent" call to the verification method. Recall that the verb template we chose earlier specifies a pair certain methods--a verification method, and an action
method--that we will call in the direct and indirect objects. For example, the verb "take" may define a
<:f200,QCourier New,>doAction = 'Take'<:f>, which means that the verification method for the direct object is
<:f200,QCourier New,>verDoTake<:f>, and the action method is <:f200,QCourier New,>doTake<:f>. The call is silent because we hide any messages that the method displays--the player will not be aware that we are making this call. However, we
<+">do<-"> take note of whether the method attempts to display any messages; if it does, the verification fails for the object. We make a list of all of the objects that survived the validity test
<+">and<-"> the verification test.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>We now have two lists: a list of <+">valid<-"> objects (objects which passed the validity test), and a list of
<+">logical<-"> objects (objects which passed the verification test).
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#4095,6624>If both lists are empty, there's no way to apply the verb to the player's noun phrase--we can't identify any objects for which the command is valid. We check to see if the player's noun phrase referred to any
<+">visible<-"></`>objects; if not, we simply display message 9 ("I don't see any %s here", where the "%s" is replaced by the words from the player's noun phrase) and abandon the command. Otherwise, we have a situation where the player referred to one or m
ore visible objects, but those objects can't be accessed for the purposes of this command. In this case, we check to see if the verb object has a
<:f200,QCourier New,>cantReach<:f> method--if so, we call the verb's
<:f200,QCourier New,>cantReach<:f> method with four parameters: the actor, a list of inaccessible direct objects, a list of inaccessible indirect objects, and the preposition. Actually, only one of these lists will ever be supplied, and the other will alw
ays be <:f200,QCourier New,>nil<:f>; when the direct object is inaccessible, the first argument has the list of inaccessible (but visible) direct objects, and the second argument is
<:f200,QCourier New,>nil<:f>. When the indirect object is inaccessible, the arguments are reversed. The preposition argument will be
<:f200,QCourier New,>nil<:f> if the command is a one-object sentence.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>For example, if a closed glass case contains a red book and a blue book, and the player types "take book," the word "book" will refer to the two books inside the case; neither of these books will be accessible for the "take" command, because they're inside
a closed container, but they're both visible. The parser will call the
<:f200,QCourier New,>cantReach<:f> method defined in the verb:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If the verb object doesn't define or inherit a <:f200,QCourier New,>cantReach<:f> method, the parser uses a different mechanism: for each visible object, it calls the object's
<:f200,QCourier New,>sdesc<:f> method, then displays message 200 (":"), then calls the
<:f200,QCourier New,>cantReach<:f> method in the object itself--<+">not<-"></`>in the verb--with the actor as the single argument.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>If the list of logical objects is empty, but the list of valid objects is not empty, the parser considers only the list of valid objects. Otherwise, it considers only the list of logical objects.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>At this point, the parser needs to determine whether the objects in the list are uniquely specified--in other words, it determines whether it has identified a single object for each singular noun phrase that the player entered. If the player types "take bo
ok," the parser must find a <+">single object<-"></`>to which "book" refers. Likewise, if the player types "take book and box," the parser must identify a single object for "book," and a single object for "box."
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If any of the noun phrases were plural, they're now finished--the player explicitly asked us to use every object matching the phrase by using a plural. For example, if the player types "take books," we will apply the command to every object which matches t
he vocabulary word "books" in its <:f200,QCourier New,>plural<:f> property.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Similarly, if a noun phrase was specified with "any," as in "take any book" or "drop any of the coins," the player has explicitly asked us to choose one of the objects matching the phrase. The parser simply picks one of the remaining objects (it picks the
first object in its internal list, but the order of objects in the internal list is unpredictable).
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>In addition, if the objects themselves are all indistinguishable from one another, the parser also picks one of the objects arbitrarily. Objects are indistinguishable if two conditions are true: first, that the objects are all derived from the exactly the
same class--that is, every object's immediate superclass is the same; and second, that the objects all have the property
<:f200,QCourier New,>isEquivalent<:f> set to <:f200,QCourier New,>true<:f>. If these two conditions hold, the parser considers the objects to be indistinguishable, and simply picks one from the list, exactly as though the user had used "any" with the noun
phrase.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#5187,6624>For a singular noun phrase, we must now have a single object. If so, we're done with the object. If more than one object remains, however, we have no way of knowing which of the remaining objects the player meant, so we must ask the player to tell us. To
do this, we check to see if the game program provides a function called
<:f200,QCourier New,>parseDisambig<:f>. If so, we call this function with two arguments: a (single-quoted) string giving the text of the noun phrase that the player typed; and a list composed of the surviving objects. If the game doesn't define a
<:f200,QCourier New,>parseDisambig<:f> function, the parser generates a message: it displays message 101 ("Which %s do you mean," with the "%s" replaced by the text entered by the player for the ambiguous noun phrase), then calls
<:f200,QCourier New,>thedesc<:f> for each surviving object, then displays message 104 ("?"). Between adjacent objects, the parse displays message 102 (","); and it also displays message 103 ("or") after the second-to-last object. Note one unusual case: i
f the ambiguous list contains a set of objects that are mutually indistinguishable, as described earlier, the parser displays only one description for the whole set of such objects, and uses
<:f200,QCourier New,>adesc<:f> instead of <:f200,QCourier New,>thedesc<:f> for the object. For example, if the player types "take coin," and the room contains a gold coin and three silver coins which are all indistinguishable from one another, the message
looks like this: "Which coin do you mean, the gold coin, or a silver coin?"
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Here's an example implementation of <:f200,QCourier New,>parseDisambig<:f>, which generates the same message that the parser would generate if
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> local i, tot, cnt;
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "Which <<<<str<;><;> do you mean, ";
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> for (i := 1, cnt := length(lst) ;
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> i <<= cnt ; ++i)
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (i << cnt) ", ";
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (i+1 = cnt) "or ";
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>After displaying prompting message, the parser lets the user enter a command using
<:f200,QCourier New,>commandPrompt<:f> code 2. If the player types something that looks like a noun phrase, the parser tries to use the new information to choose from the surviving objects. If the player simply types "all" or "both," the parser chooses al
l of the surviving object. If the player types "any," the parser chooses one of the surviving objects arbitrarily. In either case, this completes disambiguation, since the parser has identified the objects the user wishes to use in the command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>If the player types adjectives and/or nouns, the parser limits the surviving list to objects that are associated with all of the new vocabulary words. If no objects remain, the parser displays message 16 ("I don't see that here"). If exactly one object re
mains, disambiguation is complete, because the noun phrase has been resolved to a particular object. Similarly, if the player typed a noun phrase that consists of multiple objects (for example: "the red one and the blue one"), and the remaining list has t
he same number of objects as the number of noun phrases the player entered, disambiguation is completed. Otherwise, the phrase is
<+">still<-"> ambiguous, so the parser goes back and asks the user once again which of the remaining objects is to be used. Note that if
<:f200,QCourier New,>parseDisambig<:f> isn't defined, the parser displays message 100 ("Let's try it again:") before asking again.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>If the player types something that doesn't look like a noun phrase, the parser abandons the current command, and starts over at the beginning, using the new input as the next command.
@Header@<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Command Execution: Part Two
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>At this point, everything about the command is known. The parser has converted the player's words into a set of objects, with each object having a specific function in the sentence. Each component of the command--the actor, the verb, the direct object, th
e preposition, and the indirect object--has been resolved to an object or a list of objects. We have also identified the verb template, which specifies the methods that are to be called in the objects at certain points during execution. We now have all th
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>A command can refer to multiple direct objects; for example, the player can type "take the ball and the box." Fortunately, the details of handling multiple objects are entirely handled by the parser; you write the verb handlers in your game for single obje
cts only, and the parser calls these handlers as many times as necessary.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3549,6624>When the player uses multiple direct objects, either by listing several objects or by using "all," the parser checks to make sure the verb allows multiple direct objects. (In certain cases, multiple objects will be disallowed before this point. The parser
never allows multiple indirect objects, and it doesn't allow multiple direct objects for verb templates that specify the
<:f200,QCourier New,><[>disambigDobjFirst]<:f> flag.) To determine if the verb allows multiple direct objects, the parser calls the
<:f200,QCourier New,>rejectMultiDobj<:f> method in the <:f200,QCourier New,>deepverb<:f> object, passing the preposition as the argument (the argument is
<:f200,QCourier New,>nil<:f> for single-object commands). If this method returns
<:f200,QCourier New,>true<:f>, the parser terminates the command without further processing. Note that the parser doesn't display anything if
<:f200,QCourier New,>rejectMultiDobj<:f> returns <:f200,QCourier New,>true<:f>--the parser expects this method to display an appropriate error message if it returns
<:f200,QCourier New,>true<:f>. You can use <:f200,QCourier New,>rejectMultiDobj<:f> if you want to discourage the player from guessing for certain verbs.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The remainder of the processing for the command is done for each object in the direct object list. The parser goes all the way through the rest of the command processing for the first direct object, then comes back to this step and goes through the same pr
ocess for the next direct object, and so on.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Before proceeding, the parser displays the name of the current direct object if multiple direct objects are being used. If only a single object is used in the command, the parser doesn't display the object name--this is only done for multiple objects, so t
hat the player can see the results of the command for each individual object. Note that the parser displays the object name when "all" is used even if "all" ended up referring to only a single object, because the player didn't say exactly which object he o
r she meant. For the same reason, we'll display the object name when the player used "any."
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>To display the object name, the parser first calls the <:f200,QCourier New,>multisdesc<:f> method in the current object (the parser calls
<:f200,QCourier New,>sdesc<:f> instead if the object doesn't define or inherit
<:f200,QCourier New,>multisdesc<:f>--this is for compatibility with games written with previous versions of TADS, since<:f200,QCourier New,> multisdesc<:f> is a recent addition); then, it displays message 120 (":").
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Before going on, we check to see if the verb is "again," which requires special handling. This verb is used to repeat the last command. To identify this verb, TADS requires that you provide an object named
<:f200,QCourier New,>againVerb<:f>--this allows you to define the vocabulary words that are to be used for this special internal command. When the
<:f200,QCourier New,>deepverb<:f> object for the command is <:f200,QCourier New,>againVerb<:f>, the parser knows to perform the special handling necessary to repeat the last command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2457,6624>If the player types "again" as the first command of the game, the parser displays message 26 ("There's no command to repeat"), and abandons the command. Otherwise, the parser gets the information from the last command--the actor, verb, direct object, prepo
sition, and indirect object--and uses this as the new command information. Before proceeding, the parser calls the
<:f200,QCourier New,>validDo<:f> method in the <:f200,QCourier New,>deepverb<:f> to ensure that the direct object is still valid for the command, and calls
<:f200,QCourier New,>validIo<:f> to ensure that the indirect object is still valid. If either of these methods indicates that the objects are not valid, the parser displays message 27 ("You can't repeat that command") and terminates the command.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>When the verb is something other than "again," the parser saves all of the information for the current command. If the player uses "again" for the next command, it is this information that is used to repeat the command. Note that this information is saved
once for each object in a multi-object command, so if the player types "again" after typing "take the box and the ball," the command repeated is "take the ball."
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Checking with the Actor
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The next step is to check to see if the actor will allow the command. Every command is directed to an actor--if the player doesn't explicitly direct a command to an actor, it implicitly goes to the player actor,
<:f200,QCourier New,>Me<:f>. The parser calls the method <:f200,QCourier New,>actorAction<:f> in the actor object with four arguments: the
<:f200,QCourier New,>deepverb<:f> object, the current direct object, the preposition, and the indirect object. For example, for the command "take the red book," the call would look like this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3003,6624>The <:f200,QCourier New,>actorAction<:f> method can either accept the command or disallow it. To accept the command, the method need not do anything at all. To reject the command, the method should use the
<:f200,QCourier New,>exit<:f> or <:f200,QCourier New,>abort<:f> statement. If you use the
<:f200,QCourier New,>exit<:f> statement, you will disallow the command, but the turn will still be counted--that is, daemons and fuses will run as though the turn succeeded. If you use
<:f200,QCourier New,>abort<:f>, the turn doesn't count--the daemons and fuses will be skipped. In most cases, you should use
<:f200,QCourier New,>exit<:f> if you want to disallow the command in
<:f200,QCourier New,>actorAction<:f>, because the attempt to command the actor should still count as a turn. The
<:f200,QCourier New,>abort<:f> statement is intended more for "system" commands, such as "save," that are intended to happen outside of the game's world, and so shouldn't count as turns within the game.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that the parser doesn't display any messages when <:f200,QCourier New,>actorAction<:f> uses
<:f200,QCourier New,>exit<:f> or <:f200,QCourier New,>abort<:f> to disallow the command, so your
<:f200,QCourier New,>actorAction<:f> method must display an appropriate error message before exiting or aborting. Note also that this method has no return value.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Checking with the Room
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>If the actor allows the command, the next step is to determine if the actor's current location allows the command. To do this, the parser get the value of the
<:f200,QCourier New,>location<:f> property from the actor (if this isn't an object, it skips this step), then calls the
<:f200,QCourier New,>roomAction<:f> method in that object. <:f200,QCourier New,>roomAction<:f> takes five arguments: the actor, the verb, the direct object, the preposition, and the indirect object. For example, if the player types "joe, put the ball in
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>As with <:f200,QCourier New,>actorAction<:f>, the <:f200,QCourier New,>roomAction<:f> method can disallow the command by using the
<:f200,QCourier New,>exit<:f> statement. This method must display a message if it disallows the command, because the parser will simply abandon the command if
<:f200,QCourier New,>roomAction<:f> executes an <:f200,QCourier New,>exit<:f> statement. This method has no return value.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The next step is to call a general-purpose method in the indirect object, and then in the direct object. These general-purpose routines allow you to define certain behavior for an object for any verb from within a single method. You will sometimes want an
object to act a certain way for all (or nearly all) verbs; for example, if you want to create an object that's off in the distance, you will want to handle every verb except "inspect" the same way: "That's too far away." You can do this through the gener
al-purpose methods.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>First, if the command has an indirect object, the parser calls the method
<:f200,QCourier New,>iobjGen<:f> (indirect object general processing) in the indirect object. This method takes four arguments: the actor, the verb, the direct object, and the preposition.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Next, if the command has a direct object, the parser calls <:f200,QCourier New,>dobjGen<:f> in the direct object. This method also takes four arguments: the actor, the verb, the indirect object, and the preposition.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>These methods, like <:f200,QCourier New,>roomAction<:f> and <:f200,QCourier New,>actorAction<:f>, can cancel the command by using the
<:f200,QCourier New,>exit<:f> statement. These methods should display an appropriate message if they do cancel the command, since the parser will simply abandon the command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Note that the general-purpose handlers are <+">not<-"></`>called if the specific verb "overrides" them. If the object defines--not inherits, but actually defines--either a verification method or an action method for the verb, the general-purpose method is
<+">not<-"></`>executed. These methods are intended to be "catch-all" methods; if a verification or action method for a particular verb is defined for the object, the parser assumes that the verb is
<+">not<-"></`>to be handled by the catch-all method, so it skips calling the general-purpose routine.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that a verification or action method will "override" the general-purpose handler if it's defined in the same object as the general-purpose handler, or if it's defined in any subclass of the object that defines the general-purpose handler. Consider thi
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "It's too far away!";
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Now, any subclass of <:f200,QCourier New,>targetDistantItem<:f> will have
<:f200,QCourier New,>verIoThrowAt<:f> override the presence of <:f200,QCourier New,>dobjGen<:f>. Since
<:f200,QCourier New,>verIoThrowAt<:f> overrides <:f200,QCourier New,>dobjGen<:f> in
<:f200,QCourier New,>targetDistantItem<:f>, the same applies to any subclass. The same is true of
<:f200,QCourier New,>verDoInspect<:f>, because it overrides <:f200,QCourier New,>dobjGen<:f> by virtue of being defined in
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Verification and Action
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>If the command survives all of the steps so far, the parser carries out the command on the objects involved.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The first step is to verify that the command is possible. We have already determined that the objects involved in the command are accessible for the purposes of the command, but we don't know that the command can actually be applied to the object. For exa
mple, if a door is already open, trying to "open the door" should fail.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Verification is done by calling the verification method, which is specified by the verb template as discussed earlier. If there are no objects in the command, there is no verification step; we move on immediately to the action step. Otherwise, we verify f
irst the direct object, then, if the command has one, the indirect object.
<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Case 1: No Objects<-!>
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If the command has no objects, we simply call the <:f200,QCourier New,>action<:f> method defined in the
<:f200,QCourier New,>deepverb<:f> object. This method takes one argument: the actor. This method is responsible for carrying out the command; it should display an appropriate message--on either success or failure, since this is the entire command process
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The <:f200,QCourier New,>action<:f> method has no return value. It can use the
<:f200,QCourier New,>exit<:f> statement to skip any remaining commands on the same line, and it can use
<:f200,QCourier New,>abort<:f> to terminate the turn and skip running fuses and daemons. Generally, you should only use
<:f200,QCourier New,>abort<:f> with "system" commands that shouldn't count as turns. System commands, such as "save" or "restart," happen outside of the game world, so they shouldn't consume any time within the game world. For an ordinary command, even a
failed command should usually count as a turn.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Note that the <:f200,QCourier New,>action<:f> method will generally use neither
<:f200,QCourier New,>exit<:f> nor <:f200,QCourier New,>abort<:f>, even if the command fails. You should only use these statements when you want to skip the remaining commands on the same line, which should only be done if something really important happens
in the command--ordinary failures in an <:f200,QCourier New,>action<:f> routine don't usually warrant canceling the remainder of the command.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Another way of exiting an <:f200,QCourier New,>action<:f> routine is to use the
<:f200,QCourier New,>askdo<:f> statement. Executing an <:f200,QCourier New,>askdo<:f> statement lets you ask the player for a direct object, using exactly the same mechanism that the parser uses when it determines that a direct object is required--<:f200,QCourier New,>
askdo<:f> even supplies a default direct object using the same techniques as the parser. See the description of default objects (page
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>For example, when the player types "wait," the parser makes this call:
<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Case 2: Direct Object Only<-!>
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>If the command has one object, the parser starts by calling the verification method in the object. The verification method, which is named
<:f200,QCourier New,>verDo<:f><+">Verb <-">(where <+">Verb<-"> is replaced by the
<:f200,QCourier New,>doAction<:f> property value--for example, for "take," the verification method is called
<:f200,QCourier New,>verDoTake<:f>), takes one parameter: the actor.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3549,6624>If the verification method is not defined or inherited for the object, the parser disallows the command and displays an error. To display the error, the parser checks to see if the game defines a function called
<:f200,QCourier New,>parseError2<:f>. If so, it calls this function with four parameters: the verb, the direct object, the preposition, and the indirect object (note that the preposition and indirect object may be
<:f200,QCourier New,>nil<:f>); this routine is responsible for displaying an appropriate message. If this function isn't defined, the parser generates a message: it displays message 110 ("I don't know how to"), then calls the
<:f200,QCourier New,>sdesc<:f> method in the <:f200,QCourier New,>deepverb<:f> object. Then, if there's only a direct object, it displays message 111 (a space), then calls the
<:f200,QCourier New,>thedesc<:f> method in the direct object; if there's an indirect object, the parser displays message 112 ("anything"), then calls
<:f200,QCourier New,>sdesc<:f> in the preposition object (or displays message 113 ("to") if there's no preposition), then displays message 114 (a space), then calls
<:f200,QCourier New,>thedesc<:f> in the indirect object.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Here's an example implementation of <:f200,QCourier New,>parseError2<:f>, which generates the same message that the parser would use if
<:f200,QCourier New,>parseError2<:f> were not defined.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> "I don't know to how <<<<v.sdesc<;><;> ";
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f200,QCourier New,> if (d)
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Apart from this extra message, the absence of a defined or inherited verification method is equivalent to the verification method failing by displaying a message.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>If the verification method displays a message, the command is terminated; the parser proceeds with the next direct object in the same command, or moves on to the next command on the command line. The verification method doesn't have a return value--it indi
cates failure by displaying a message, and indicates success by displaying nothing.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Note that verification methods must <+">not<-"></`>make any changes to game state--they must never set the object of a property, or call any built-in functions with side effects (for example, never call
<:f200,QCourier New,>restart<:f> or <:f200,QCourier New,>askfile<:f> from within a verification method). Verification methods can be called "silently," which means that the parser hides any messages they generate from the player--see the section on resolvi
ng objects (page <:X3,-16384;PageRef ObjectResolution>94<:X~3,-16384;PageRef ObjectResolution>) for details. The parser is simply testing various possibilities when making these silent calls, and hasn't committed to a course of action yet, so these calls m
ust not have any effect on the game state.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>If the verification test succeeds--in other words, the verification method doesn't display any messages--the parser calls the action method in the direct object. The action method is named
<:f200,QCourier New,>do<+"><:f>Verb<-"> (for example, the action method for "take" is called
<:f200,QCourier New,>doTake<:f>). Note that the <:f200,QCourier New,>do<:f> in
<:f200,QCourier New,>doTake<:f> stands for "direct object"--it's not the word "do." The action method is called with one parameter: the actor.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>The action method is responsible for carrying out the command. It should display an appropriate message--both on success and on failure, because this is the entire processing of the command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that it's possible for the action method to reject the command, even though the verification method allowed it. If the action method wants to apply a tougher standard to the conditions under which the command can succeed, it can do so without any prob
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>For example, when the player types "take red book," the parser calls these methods:
<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>Case 3: Direct and Indirect Objects<-!>
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>When both a direct and an indirect object are specified, the verification sequence involves
<+">both<-"></`>objects. First, the parser checks to make sure that the verification methods are defined or inherited for both objects; if not, the command fails, and the parser displays a message as described above for Case 2.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The parser first verifies the direct object. It does this by calling
<:f200,QCourier New,>verDo<+"><:f>Verb<-"> in the direct object. For a normal verb, whose the verb template does
<+">not <-">define the <:f200,QCourier New,><[>disambigDobjFirst]<:f> flag, this method takes two parameters: the actor, and the indirect object. Otherwise, the only parameter is the actor.
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,>If the direct object verification is successful, we verify the indirect object by calling
<:f200,QCourier New,>verIo<+"><:f>Verb<-"> in the indirect object. For a normal verb, whose template does not specify
<:f200,QCourier New,><[>disambigDobjFirst]<:f>, this method takes only one parameter: the actor. For verb templates that
<+">do<-"> specify the <:f200,QCourier New,><[>disambigDobjFirst]<:f> flag, this method takes two parameters: the actor, and the direct object.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>If either verification method displays a message, the command fails, and we proceed to the next direct object of the current command, or to the next command on the command line if there are no more direct objects for the current command.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>If both verification methods succeed, we call the action method for the verb template. The action method for a two-object command is
<+">always<-"> called in the <+">indirect<-"> object. The method is called
<:f200,QCourier New,>io<+"><:f>Verb<-">, and takes two parameters: the actor, and the direct object. (Note that the direct object is always included in this call, regardless of any special flags in the verb template.) As with a single-object action metho
d, this action method is responsible for carrying out the command, and must display an appropriate message, whatever the outcome of the command.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that the parser will <+">not<-"></`>call any action method in the direct object for a two-object command. Your action method in the indirect object is free to call a method in the direct object if you wish to have a direct object method process the co
mmand, but the parser will never call such a method directly.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>For example, if the player types "put ball in box," the parser makes these calls:
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Daemons and Fuses
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>After processing the verification and action methods, the command is finished. The parser goes back and processes the next direct object in the same command, as described earlier. The steps above are repeated for each direct object in the list.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Once all of the direct objects have been processed for a particular command, the turn is over. Even if the command line has additional commands following the current command, the parser considers the current command to be a complete turn--the additional co
mmands will be processed, but will be counted as additional turns. So, once all of the direct objects have been processed for a command, the parser executes the daemons and fuses.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The parser first executes the daemons. The order in which the daemons are executed is arbitrary; it depends on the (unpredictable) order in which the system builds its internal lists as daemons are added and removed. The parser executes all active daemons
set with the <:f200,QCourier New,>setdaemon()<:f> built-in function, then executes all active daemons set with the
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Next, the parser executes any active fuses that has "burned down." As with daemons, the order in which fuses are executed is arbitrary and unpredictable. The system first executes any fuses set with the
<:f200,QCourier New,>setfuse()<:f> function, then executes any fuses set with the
<:f200,QCourier New,>notify()<:f> function. Before executing each fuse, the parser removes it from the list of active fuses. Only fuses that have burned down are executed; others are left to be processed when they're ready.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Note that the fuse timer is entirely under the control of your game program. The only time that fuse timers are advanced is when you call the
<:f200,QCourier New,>incturn()<:f> built-in function. This function advances all fuse timers by one turn (or by a specified number of turns, if you provide an argument), and marks any fuses that burn down as being ready for execution. The
<:f200,QCourier New,>incturn()<:f> function doesn't actually execute any fuses, but merely advances their timers.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624><:ZVerbSynonyms><:Z~VerbSynonyms>Verb Synonyms and Verb Redirection
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>TADS has a couple of convenience features that make it easy to create certain common definitions.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>First, TADS lets you define object-level verb synonyms. It's often desirable to make a number of verbs work the same way with a particular object, because different users will try to do the same thing with slightly different commands. For example, if you
have a touch-pad on a control panel in your game, the player may try a number of different verbs with it: touch, push, tap, press. "Push" and "press" are already synonymous in adv.t (they both refer to
<:f200,QCourier New,>pushVerb<:f>), but "touch" is a separate verb, and "tap" isn't even defined, so you would have to add this verb in your game program. Since "touch" and "tap" are separate verbs from "push," you will need to make the touch pad object re
spond to all three verification methods and all three action methods the same way. You
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>This is tedious, though--especially if you have more than two or three verbs that you want to make synonymous. Instead of these lengthy definitions, you can use the TADS object-level verb synonym feature. To do this, you use the special pseudo-property
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>This simple definition has the same effect as the much lengthier definitions above. The way to read this definition is: the direct-object verb synonym for "touch" is "push."
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>You can specify that more than one verb is a synonym for another verb. To do this, simply list all of the different verb synonyms on the right-hand side of the equals sign:
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Read this definition as: the direct-object verb synonyms for "touch" are "push" and "tap." Note that the fact that you can use multiple verbs on the right-hand side may make it easier to remember which way this direction works. All of the verbs in the co
mmand are redirected to a single verb, so the "target"--the verb handler that's actually called when any of these verbs are used--must be in the position where only one verb can go, which is inside the parentheses. So, if the player types "push pad," the p
arser will call <:f200,QCourier New,>verDoTouch<:f> and <:f200,QCourier New,>doTouch<:f>.
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624><:f200,QCourier New,>ioSynonym<:f> works the same way, but maps the
<:f200,QCourier New,>verIo<+"><:f>Verb<-"> and <:f200,QCourier New,>io<+"><:f>Verb<-"> handlers of one or more verbs to those of another verb. Whereas
<:f200,QCourier New,>doSynonym<:f> makes one or more verbs synonymous when the object is used as a direct object,
<:f200,QCourier New,>ioSynonym<:f> makes verbs synonymous when the object is used as an indirect object.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Note that verb synonyms created with <:f200,QCourier New,>doSynonym<:f> and
<:f200,QCourier New,>ioSynonym<:f> apply only to the object in which they are defined. A verb synonym created for one object doesn't affect any other objects, so "touch" and "push" are still separate verbs for other objects. Of course, verb synonyms are i
nherited just like any other verb handler.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>The second convenience feature lets you specify that when a verb is applied to a particular object, it should instead be applied to a different object. This is often convenient when you are composing a complex object in your game from several internal obje
cts. For example, you might want to include a desk with a drawer. The desk and drawer are separate objects, but the player may type "open desk" to open the drawer. You could code this by redirecting the verb verification and action methods for "open" fro
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>This works, but redirecting more verbs would be tedious--and you'd probably want to redirect at least "close," and probably "look in" and "put in" as well. To avoid the large amount of typing this would involve, you can use the verb handler redirection syn
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>(Note that the symbol "<:f200,QCourier New,>-<;><:f>" is made up of a hyphen followed by a greater-than sign.) This single line replaces the
<:f200,QCourier New,>verDoOpen<:f> and <:f200,QCourier New,>doOpen<:f> definitions above. It indicates that both the
<:f200,QCourier New,>doOpen<:f> and <:f200,QCourier New,>verDoOpen<:f> methods, when called on the desk, should be redirected to the drawer.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>For the most part, TADS doesn't treat the player actor's object, <:f200,QCourier New,>Me<:f>, any differently from any other actor in the game. When the player types a command that isn't explicitly directed to another actor, TADS assumes that the actor is
<:f200,QCourier New,>Me<:f>, and from that point on acts the same as it would if the command were being directed to any other actor.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>All of the command handling methods that the parser calls have the current actor object as a parameter, which allows them to be written independently of actor--or, if desired, to take special actions for certain actors. The verb handlers in adv.t generally
treat all actors the same. For example, the definition of <:f200,QCourier New,>doTake<:f> in the class
<:f200,QCourier New,>thing<:f> doesn't move the object being taken into the player's inventory, but rather into the current actor's inventory. This allows commands such as "take the box" and "joe, take the box" to be processed using the same code.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>If a command handler is written independently of the actor, it needs to be able to display its messages in terms of the actor carrying out the command, rather than simply in terms of "you." It would be very inconvenient if you had to call
<:f200,QCourier New,>actor.thedesc<:f> every time you wrote a message in a verb handler, so TADS provides a much more convenient mechanism called "format strings."
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>A format string is a special sequence of characters that signals the output formatter to substitute a property of the current command's actor. Instead of using "you" and related words, the messages in adv.t use format strings; your game program should do t
he same thing any place where an actor other than the player may be taking some action that results in a message.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>A format string associates a special character sequence with a property name. When a message includes a format string, enclosed in percent signs (%), the output formatter removes the format string and replaces it by calling the property associated with the
format string. For example, one of the format strings defined in adv.t is:
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>This tells the system that whenever it sees "%you%" in a message being displayed, it removes the "%you%" sequence, and replaces it with the text that results from evaluating the property
<:f200,QCourier New,>fmtYou<:f> in the current actor.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>You can define new format strings of your own, although adv.t defines most of the format strings you'll probably need.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>In adv.t, most messages are phrased in terms of format strings. For example, when the player tries to travel a particular direction but can't, adv.t doesn't display "You can't go that way," but instead displays "%You% can't go that way." When the player t
ries to go east but can't, the system displays "You can't go that way," just as it would have if the format string hadn't been used. But, when the player types "joe, go east," the system displays "Joe can't go that way," because
<:f200,QCourier New,>joe.fmtYou<:f> displays "joe" rather than "you."
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Note that the capitalization of the replacement text follows the capitalization of the format string itself. So, "%you%" becomes "you," while "%You%" becomes "You." ("Joe" is displayed capitalized in either case if the message displayed by
<:f200,QCourier New,>joe.fmtYou<:f> is itself capitalized.)
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Note that many format strings are defined for other parts of the sentence. When writing a message, you will usually have to use several format strings to keep the sentence grammatical. For example:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>This message will become "You aren't wearing your spacesuit" when displayed for the player character, but will become "Joe isn't wearing his spacesuit" when displayed for Joe.
@Header@<:s><:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Compound Words
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>TADS can only handle prepositions that consist of a single word. Unfortunately, English and other human languages have constructions in which multiple words are used for the function of a single preposition in a sentence; for example, "take the book out of
the bag" has two prepositions in a row, "out of," serving the function of a preposition in the sentence.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Although TADS doesn't have any way to specify a sentence template that uses multiple prepositions like this, it
<+">does<-"></`>provide a mechanism that lets you specify that certain pairs of words are "glued together" into a single word when they occur together. In the example above, you could define "out of" as such a pair of words: whenever the parser sees "out"
followed directly by "of," it can be made to put these two words together and treat the pair as a single word.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>To define a pair of words that should be treated as a single word, you use the
<:f200,QCourier New,>compoundWord<:f> statement. For example:
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>This specifies that when the parser sees the word "out," followed directly by the word "of," it should take the pair of words and replace it with the single word "outof." (Note this replacement word follows the convention in adv.t, which is to simply conca
tenate the two words to form the replacement word, but the replacement can be anything at all--you could have made the replacement word, for example, "out_of.")
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Note that you must still define "outof" as a preposition. Even though "out" and "of" are separately defined as prepositions, the result of a compound word replacement must
<+">also<-"></`>be defined as a vocabulary word. Once the pair of words is replaced with the compound word, the parser forgets ever knowing about the pair as separate words.
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>You can't directly define three-word (or longer) compound words, but you can
<+">indirectly<-"></`>do so by constructing the longer words from two-word directives. For example, to convert "out from under" into a single preposition, you would use two compound word definitions:
<:s><:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>When the parser finds the sequence "out from under," it first converts "out from" into "outfrom." Then, it checks the sentence again, and finds the pair "outfrom under," which is converts to "outfromunder."
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Special Words
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The parser treats a number of words as special reserved words. These words aren't ordinary vocabulary words, because they don't fit in to the parts of speech used for normal vocabulary words--they aren't nouns, plurals, adjectives, articles, verbs, or prep
ositions. Since they aren't ordinary vocabulary words, you can't define them using the normal vocabulary definitions; instead, you use a separate command to specify these words: the
<:f200,QCourier New,>specialWords<:f> statement.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>This command can appear anywhere that one of the other special commands (such as
<:f200,QCourier New,>formatstring<:f> or <:f200,QCourier New,>compoundWord<:f>) is allowed. Following the
<:f200,QCourier New,>specialWords<:f> keyword, you list all of the special words in a fixed order. You must specify the words in the order shown below, and you must provide at least one word for every position. You can provide more than one word for each
position, by listing each synonym separated by an equals sign (=). The default list, which matches the built-in list if no
<:f200,QCourier New,>specialWords<:f> command is used in your game, looks like this:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Except for the words in the "of," "one," and "ones" positions, the words specified in the list can't be used as ordinary vocabulary words at all--they're always considered to have their special meaning as listed here. The slots for "of," "one," and "ones"
are <+">not<-"></`>reserved in ordinary use; their special meanings are in effect only when the parser expects them according to context.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Note that the slot occupied by "any" is a recent addition. You can omit this position in a
<:f200,QCourier New,>specialWords<:f>, in which case the system will use the default ("any" and "either" will be used as synonyms for this position).
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3276,6624>You can use the special <:f200,QCourier New,>replace<:f> and <:f200,QCourier New,>modify<:f> commands with
<:f200,QCourier New,>specialWords<:f>. If your statement starts off with
<:f200,QCourier New,>replace specialWords<:f>, any previous special words definitions are discarded, and the new set is used. (Note that the same thing happens if you specify a second
<:f200,QCourier New,>specialWords<:f> directive in your game program with neither a
<:f200,QCourier New,>replace<:f> nor <:f200,QCourier New,>modify<:f> prefix, but the compiler will warn you that you should use
<:f200,QCourier New,>replace<:f> to make your intentions explicit.) If your statement starts off with
<:f200,QCourier New,>modify specialWords<:f>, the compiler <+">adds<-"></`>the special words in the new list to the words that have already been defined in previous
<:f200,QCourier New,>specialWords<:f> statements. When using <:f200,QCourier New,>modify<:f>, you can use
<:f200,QCourier New,>nil<:f> in any slot to indicate that you don't wish to add any words to that position. You can therefore use
<:f200,QCourier New,>modify<:f> as a means of adding a new special word or words to one or more slots, without having to specify the entire list again.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>When an error occurs during parsing, the parser tells the user what went wrong with as specific an error message as possible. One of the design goals of the parser is to be friendly to players; although error messages are inherently somewhat unfriendly, the
y certainly can't be eliminated entirely, so we at least try to make them informative. The player should always be able to understand why the game rejects a command, so that he or she can figure out what to say instead.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The parser lets your game program provide a custom message for every error. Most errors are handled through the function
<:f200,QCourier New,>parseError<:f>--if your game defines this function, the parser will call it whenever it wants to display an error. A few parser messages are more specialized, and use different functions that you can optionally provide.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>The parser calls the <:f200,QCourier New,>parseError<:f> function with two parameters: a message number, and the text of the default message. The message number identifies the reason the parser is displaying a message--each situation that requires a messag
e is given its own message number. The default message is the text that the parser would have displayed if you did not define a
<:f200,QCourier New,>parseError<:f> function in your game at all.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>You may have noticed references to message numbers elsewhere in this chapter--these were referring to
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Your <:f200,QCourier New,>parseError<:f> function should return either
<:f200,QCourier New,>nil<:f> or a (single-quoted) string value. If your
<:f200,QCourier New,>parseError<:f> function returns <:f200,QCourier New,>nil<:f>, it means that you want to use the default message--this is the same as not defining a
<:f200,QCourier New,>parseError<:f> function at all. If your function returns a string value, the string is displayed in place of the parser's default message.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Note that a few of the default messages contain the sequence "%s". This special sequence is replaced in the actual message displayed by a string value of some sort; for example, in message 2, the "%s" is replaced with the unknown word. Similarly, the specia
l sequence "%c" in message is replaced with a single character, and "%d" is replaced by a number. You can use a "%" sequence in any message you provide to replace a message where the default text uses the same special sequence.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2184,6624>Messages with numbers below 100 are complete messages--they're not part of more complex messages built out of pieces. Messages 100 and above are different: they're fragments of complete messages; several such fragments are combined (sometimes with other t
ext as well) to form a complete message. So, if you want to do some special formatting, such as enclosing any parser error messages in parentheses, you can easily do so for any of the regular messages, and avoid doing so for the complex messages, you can s
imply check the message number to make sure it's less than 100, and apply your special formatting if so.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624> Most of the messages in the first group are self-explanatory, although a few require some explanation.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1911,6624>Messages 3, 10, and 11 are generated if a word the player uses refers to more than a fixed number of objects in the game. Note that the limit applies regardless of whether the objects are all present or not--the limit is for the total number of objects in t
he entire game with the same vocabulary word. (For this reason, it's probably not a good idea to define a noun or adjective in a very general class such as "thing" or "item".) The limit in version 2.2 is 200 objects; prior to 2.2 it was 100 objects.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1638,6624>Message 9 is generated if the words the player uses to refer to an object are not all defined for at least one object. For example, if your game has a blue book, and a red box, the words "red" and "blue" will both be recognized as adjectives, and "book" and
"box" as nouns; if the player types "look at red book," the phrase "red book" will be recognized as a valid noun phrase in form, but it doesn't refer to any object defined in the game. The parser will respond with message 9.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>Messages 13 and 14 are used for pronouns. When the player refers to one of the singular pronouns (it, her, and him), and the object that the pronoun represents is no longer accessible, message 13 is used. Message 14 is used with the pronoun "them."
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Message 15 is used when the player uses "all" as the object of a command, but there are no suitable objects present.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>Message 28 is displayed when the player enters a command with multiple direct objects for a verb that requires the direct object to be disambiguated first. Verbs that process the direct object first accept only one direct object.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Message 30 is displayed when the player enters a command like "take 3 balls," but fewer such items are present.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>When the player addresses a command to an actor, and the actor is visible to the player (the actor's
<:f200,QCourier New,>isVisible(Me)<:f> returns <:f200,QCourier New,>true<:f>), but the actor is not a valid actor (the actor's
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>1 I don't understand the punctuation "%c".
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>2 I don't know the word "%s".
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>3 The word "%s" refers to too many objects.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>4 I think you left something out after "all of".
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>5 There's something missing after "both of".
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>6 I expected a noun after "of".
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>7 An article must be followed by a noun.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>8 You used "of" too many times.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624> <+">Note: message 8 is no longer used.<-">
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>9 I don't see any %s here.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>10 You're referring to too many objects with "%s".
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>11 You're referring to too many objects.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>12 You can only speak to one person at a time.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>13 I don't know what you're referring to with '%s'.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>14 I don't know what you're referring to.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>15 I don't see what you're referring to.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>16 I don't see that here.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>17 There's no verb in that sentence!
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>18 I don't understand that sentence.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>19 There are words are your command I couldn't use.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>20 I don't know how to use the word "%s" like that.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>21 There appear to be extra words after your command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>22 There seem to be extra words in your command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>23 internal error: verb has no action, doAction, or ioAction
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>24 I don't recognize that sentence.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>25 You can't use multiple indirect objects.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>26 There's no command to repeat.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>27 You can't repeat that command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>28 You can't use multiple objects with this command.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>29 I think you left something out after "any of".
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>30 I only see %d of those.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>31 You can't talk to that.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>32 Internal game error: preparseCmd returned an invalid list
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>33 Internal game error: preparseCmd command too long
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>34 Internal game error: preparseCmd loop
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The next set of messages is used to ask questions when the player refers to an object with words that could refer to more than one object. The parser must in these cases ask the player which of the possible objects was meant. Note that these messages will o
nly be used if your game does not define a <:f200,QCourier New,>parseDisambig<:f> function, which will be used instead if defined.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>100 Let's try it again:
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>101 Which %s do you mean,
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>The next set is used when an object is not suitable for a verb. These messages are needed when a player uses a verb with an object, but the object does not define (or inherit from a superclass) an appropriate "verification" method (verDo<+">Verb<-"> or verI
o<+">Verb<-">). Messages 111 and 114 consist of a single space.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Note that these messages are not used if your game defines a <:f200,QCourier New,>parseError2<:f> function, since that function will be called instead to display this error.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>110 I don't know how to
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>The next message is used after each object when multiple objects are listed. For example, when the player enters the command "take all," the parser will apply the verb "take" to each accessible object in sequence; before applying the verb to each object, th
e parser displays the name of the object, followed by this message, so that the player can see the results of the command for each object.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#2730,6624>The next messages are used to note objects being used by default. When the player types a command that omits an object, and the parser can determine that the verb implies that a particular object is being used, the parser will display the name of the object
with these messages. For example, if the player types "dig", the parser might determine that the direct object is implicitly the ground, the preposition is "with," and the indirect object is implicitly the shovel; in this case, it will display message 130,
then the name of the ground, then message 131; then it will display message 130 again, then the name of the assumed preposition, then message 132, then the name of the shovel, then message 131. Message 132 consists of a single space.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Note that these messages won't be used if your game defines a <:f200,QCourier New,>parseDefault<:f> function.
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624>When the player leaves out the object in a command, but the parser is
<+">not<-"></`>able to find a suitable default object, the parser will ask the player to supply an object using these messages.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624>Note that these messages aren't used if your game defines a <:f200,QCourier New,>parseAskobj<:f> or
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>140 What do you want to
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>141 it
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>142 to
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>144 them
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>145 him
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>146 her
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>147 them
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>148 What do you want
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624>149 to
<:s><:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624>When the player uses words that could refer to more than one object, and the objects in question are visible but not accessible, the parser will call the
<:f200,QCourier New,>cantReach<:f> method in each of the objects after displaying the name of the object and message 200.
<:I0,360,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>Here's a sample of a <:f200,QCourier New,>parseError<:f> function that encloses any of the regular messages in square brackets. It ignores any messages that aren't in the simple message range (below 100), since messages outside this range are fragments of
more complicated messages, so can't be formatted as though they were entire messages.
@Header@<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#370,6624>Summary of Properties, Methods, Objects, and Functions
<:I0,432,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624>As described throughout this chapter, the parser calls certain methods that objects in your game can define, and calls certain functions that your game can provide. All of these methods and functions are described in detail in this chapter. This section s
ummarizes these properties and function; for full information, refer to the appropriate section earlier in this chapter.
<:I0,0,0,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f240,2MinioMMSC_367 RG 585 NO 11 OP,><+!>Properties and Methods<-!><:f>
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>action(<+">actor<-">)<-!>: Called in a <:f200,QCourier New,>deepverb<:f> object during command execution to execute a command with no objects.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>actorAction(<+">verb, dobj, prep, iobj<-">)<-!>: Called in the actor object during command execution.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>adesc<-!>: Used to display an object's short description with an indefinite article.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>adjective<-!>: Defines words as adjectives, and associates them with the object.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>article<-!>: Defines words as articles.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>cantReach(<+">actor<-">)<-!>: Called in an object (only if <:f200,QCourier New,>cantReach<-"><-"><:f> isn't defined in the verb) when the object is visible but not accessible; this method is meant to display an explanation of this condition.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>cantReach(<+">actor, dolist, iolist, prep<-">)<-!>: Called in a verb when the list of objects (only one of
<+">dolist<-"></`>or <+">iolist<-"> will be non-nil) is visible but not accessible; this method is meant to display an explanation.<-"><-">
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!><-">construct<-!>: Called immediately after an object is created with the
<:f200,QCourier New,>new<:f> operator. Minimally, his method should install the object into its container's
<:f200,QCourier New,>contents<:f> list.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>contents<-!>: The list of an object's contents.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>destruct<-!>: Called immediately before an object is destroyed with the
<:f200,QCourier New,>delete<:f> operator. Minimally, this method should remove the object from its container's
<:f200,QCourier New,>contents<:f> list, and should make sure that the object is not referenced from any other lists or properties.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>doAction<-!>: Direct Object Action; associated with a <:f200,QCourier New,>deepverb<:f> object Defines the verb template for a single-object command for a verb, and specifies the suffix for to be used for the action and verification methods for the ve
rb (<:f200,QCourier New,>do<+"><:f>Suffix<-"> and <:f200,QCourier New,>verDo<+"><:f>Suffix<-">, respectively).
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>dobjGen(<+">actor, verb, iobj, prep<-">)<-!>: General direct object handler, called during command execution on the direct object prior to processing the verb's verification and action routines.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>doDefault(<+">actor, prep, iobj<-">)<-!>: Direct Object Default. Associated with a
<:f200,QCourier New,>deepverb<:f> object. Returns the list of default objects for the verb.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>ioAction(<+">prep<-">)<-!>: Indirect Object Action; associated with a
<:f200,QCourier New,>deepverb<:f> object. Defines the verb template for a two-object command for a verb with the given preposition, and specifies the suffix for to be used for the action and verification methods for the verb (<:f200,QCourier New,>io<+"><:f>
Suffix<-"> and <:f200,QCourier New,>verIo<+"><:f>Suffix<-">, respectively).
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>iobjGen(<+">actor, verb, dobj, prep<-">)<-!>: General indirect object handler, called during command execution on the indirect object prior to processing the verb's verification and action routines.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>ioDefault(<+">actor, prep<-">)<-!>: Indirect Object Default; associated with a
<:f200,QCourier New,>deepverb<:f> object. Returns the list of default objects for the verb.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>isEquivalent<-!>: Used to determine if an object should be treated as equivalent to other objects of its immediate superclass. If this property is
<:f200,QCourier New,>true<:f>, the parser treats all objects of the same immediate superclass as this object as interchangeable during disambiguation.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>isHim<-!>: If <:f200,QCourier New,>true<:f>, the object can be the antecedant for the pronoun "him."
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>isHer<-!>: If <:f200,QCourier New,>true<:f>, the object can be the antecedant for the pronoun "him."
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>isVisible(<+">vantage<-">)<-!>: Used to determine if an object is visible from the given object. The parser uses this to determine how to complain when an object isn't accessible: if it's visible, but not accessible, the parser will use
<:f200,QCourier New,>cantReach<:f> to complain, otherwise it will simply say "I can't see that here."
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>location<-!>: The object which contains the object.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>locationOK<-!>: If this property is <:f200,QCourier New,>true<:f>, it tells the compiler that you know that the
<:f200,QCourier New,>location<:f> property is not an object constant, and the compiler therefore suppresses the warning it would otherwise generate.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>multisdesc<-!>: Used by the parser to display the current object when iterating through a list of direct objects in a command.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>nilPrep<-!>: Associated with a <:f200,QCourier New,>deepverb<:f> object; used by the parser to determine the preposition to use when a command of the form VERB IOBJ DOBJ is entered. If undefined, the preposition object associated with the word "to" is
used by default.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>noun<-!>: Defines words as nouns, and associates them with the object.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>plural<-!>: Defines words as plurals, and associates them with the object.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>preferredActor<-!>: Used by the parser to determine if an object is a "preferred" actor; if this property is
<:f200,QCourier New,>true<:f>, the object is chosen as the actor in cases where the actor is ambiguous and none of the other objects are preferred actors.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>prepDefault<-!>: Associated with a <:f200,QCourier New,>deepverb<:f> object. The parser uses this property to find the default preposition object to use when the player enters a partial command that starts with the verb and a direct object, but omits
the preposition and indirect object.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>preposition<-!>: Defines words as prepositions, and associates them with the object.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>rejectMultiDobj(<+">prep<-">)<-!>: Associated with a <:f200,QCourier New,>deepverb<:f> object. If this method returns
<:f200,QCourier New,>true<:f>, the verb doesn't allow multiple direct objects or "all."
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>roomAction(<+">actor, verb, dobj, prep, iobj<-">)<-!>: Called in the actor's location during command execution.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>roomCheck(<+">verb<-">)<-!>: Called in the actor at the beginning of execution, before object disambiguation.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>sdesc<-!>: Short description. Used by the parser to display an object's name.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>statusLine<-!>: Called in the actor's location to update the statue line.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>thedesc<-!>: Displays the object's name with a definite article.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>validActor<-!>: Called by the parser to determine if the object is valid as an actor. This method doesn't check to see if the object is
<+">logical<-"> to use as an actor, but simply if the object is <+">accessible<-"></`>as the target of a command.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>validDo(<+">actor, obj, seqno<-">)<-!>: Associated with a <:f200,QCourier New,>deepverb<:f> object. Returns
<:f200,QCourier New,>true<-"><:f> if the object is accessible as a direct object for the verb.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>validDoList(<+">actor, prep, iobj<-">)<-!>: Associated with a
<:f200,QCourier New,>deepverb<:f> object. Returns a list of possibly-valid direct objects for the verb. The objects returned will be tested for validity with
<:f200,QCourier New,>validDo<:f>, so the list can contain invalid objects as well, but it must contain
<+">all<-"></`>of the valid direct objects for the verb.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>validIo(<+">actor, obj, seqno<-">)<-!>: Associated with a <:f200,QCourier New,>deepverb<:f> object. Returns
<:f200,QCourier New,>true<-"><:f> if the object is accessible as an indirect object for the verb.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>validIoList(<+">actor, prep, dobj<-">)<-!>: Associated with a
<:f200,QCourier New,>deepverb<:f> object. Returns a list of possibly-valid indirect objects for the verb. The objects returned will be tested for validity with
<:f200,QCourier New,>validI<:f><:f200,QCourier New,>o<:f>, so the list can contain invalid objects as well, but it must contain
<+">all<-"></`>of the valid indirect objects for the verb.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>value<-!>: The parser sets this property of the <:f200,QCourier New,>strObj<:f> or
<:f200,QCourier New,>numObj<:f> object to the actual value of the string or number (respectively) entered in a command.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>verb<-!>: Defines words as verbs, and associates them with the object. Strings in this list can consist of one or two words; the second word must also be separately defined as a preposition.
<:I0,0,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f240,2MinioMMSC_367 RG 585 NO 11 OP,><+!>Objects<-!><:f>
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>againVerb<-!>: The <:f200,QCourier New,>deepverb<:f> object with the vocabulary for "again." The parser internally handles the "again" processing when this verb's vocabulary word is entered as the command.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>Me<-!>: The player actor object. When a command is not explicitly directed to another actor, this object is the actor to which the command is sent.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>numObj<-!>: A special object which is used as the direct object when a number is entered in a command (such as in "enter 30 on calculator," in which
<:f200,QCourier New,>numObj<:f> is the direct object). The <:f200,QCourier New,>value<:f> property is set to the number actually entered in the command.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>strObj<-!>: A special object which is used as the direct object when a quoted string is entered in a command (such as in 'type "hello" on keyboard,' in which
<:f200,QCourier New,>strObj<:f> is the direct object). The <:f200,QCourier New,>value<:f> property is set to the string actually entered in the command.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><+!>takeVerb<-!>: Formerly required, but no longer directly used by the parser.
<:I0,0,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#273,6624><:f240,2MinioMMSC_367 RG 585 NO 11 OP,><+!>Functions<-!><:f>
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>commandPrompt(<+">type<-">)<-!>: The parser calls this function, if defined, to display the prompt before asking for a command. The
<+">type<-"></`>code specifies the type of input being requested.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>init<-!>: The system calls this immediately after loading the game, and again whenever the game is restarted. This function can perform any startup operations, such as setting fuses and daemons, and displaying an introductory message.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#546,6624><+!>pardon<-!>: The parser calls this function whenever the player enters an empty command. You can display an error message, if you wish.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624><+!>parseAskobj(<+">verb, ...<-">)<-!>: The parser calls this function, if defined, to prompt for a missing direct or indirect object. If
<:f200,QCourier New,>parseAskobjActor<:f> is defined, <:f200,QCourier New,>parseAskobj<:f> is ignored. If two arguments are provided, an indirect object is being requested, and the second argument is a preposition (which may be
<:f200,QCourier New,>nil<:f>); otherwise, a direct object is being requested.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624><+!>parseAskobjActor<-!><+!>(<+">actor, verb, ...<-">)<-!>: The parser calls this function, if defined, to prompt for a missing direct or indirect object.<-"> If three arguments are provided, an indirect object is being requested, and the third argument i
s a preposition (which may be <:f200,QCourier New,>nil<:f>); otherwise, a direct object is being requested.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>parseDefault<-!><+!>(<+">obj, prep<-">)<-!>: The parser calls this function, if defined, to display a message indicating that the object (and the preposition, if not
<:f200,QCourier New,>nil<:f>) are being used by default.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1365,6624><+!>parseDisambig<-!><+!>(<+">nameString, objList<-">)<-!>: The parser calls this function, if defined, to prompt for more information when the player enters an ambiguous object name. The
<+">nameString<-"> is the string of words entered by the player (given as a single-quoted string), and the
<+">objList<-"> is a list of the objects matching the name.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>parseError<-!><+!>(<+">num, str<-">)<-!>: The parser calls this function, if defined, to get the text of an error message.
<+">num<-"> is the message number, and <+">str<-"> is the text of the message that the parser would display by default if this function weren't defined.<-">
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#1092,6624><+!>parseError2(<+">verb, dobj, prep, iobj<-">)<-!>: The parser calls this function, if defined, to display a message indicating that the verb can't be applied to these objects (because one of the objects doesn't define or inherit a verification method for
the verb).<-">
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#3549,6624><+!>preinit<-!>: Called by the <+">compiler<-">, after compilation is complete, to perform any desired initialization. This function can't set any fuses or daemons, or display any messages; these functions are not saved in the compiled game file, so they
must wait until the <:f200,QCourier New,>init<:f> function, which is invoked at run-time. The
<:f200,QCourier New,>preinit<:f> function is intended to perform any time-consuming computation--for example, setting up lists of objects or initializing property values--that would otherwise be done in
<:f200,QCourier New,>init<:f> every time the game is started. By performing these functions in
<:f200,QCourier New,>preinit<:f>, the work can be done at compile-time, saving players from having to wait for it each time they run the game. Note that this function won't be called until run-time if the game is compiled for debugging; while this doesn't
affect the behavior of the game (apart from slowing down run-time startup), it allows you to use the debugger to step through your
<:f200,QCourier New,>preinit<:f> function.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>preparse(<+">cmd<-">)<-!>: The parser calls this function with a (single-quoted) string giving the full text of the command line each time the player enters a new command.
<:I0,162,432,0><:R1,15,1,720,1,1080,1,1440,1,1810,1,2160,1,2530,1,2880,1,3600,1,4320,1,5040,1,5760,1,6480,1,7200,1,7920,1,8640,><:#819,6624><+!>preparseCmd<-!><+!>(<+">wordList<-">)<-!>: The parser calls this function with a list of (single-quoted) strings giving the words of the current command. This function is called for each individual command on a command line.